home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / ownrdclb / odcbolst.ctl < prev    next >
Text File  |  1998-06-28  |  109KB  |  2,974 lines

  1. VERSION 5.00
  2. Begin VB.UserControl OwnerDrawComboList 
  3.    ClientHeight    =   645
  4.    ClientLeft      =   0
  5.    ClientTop       =   0
  6.    ClientWidth     =   2865
  7.    KeyPreview      =   -1  'True
  8.    ScaleHeight     =   645
  9.    ScaleWidth      =   2865
  10.    ToolboxBitmap   =   "ODCboLst.ctx":0000
  11.    Begin VB.PictureBox picRes 
  12.       AutoRedraw      =   -1  'True
  13.       AutoSize        =   -1  'True
  14.       BorderStyle     =   0  'None
  15.       Height          =   240
  16.       Left            =   120
  17.       Picture         =   "ODCboLst.ctx":00FA
  18.       ScaleHeight     =   240
  19.       ScaleWidth      =   1920
  20.       TabIndex        =   0
  21.       Top             =   60
  22.       Visible         =   0   'False
  23.       Width           =   1920
  24.    End
  25. End
  26. Attribute VB_Name = "OwnerDrawComboList"
  27. Attribute VB_GlobalNameSpace = False
  28. Attribute VB_Creatable = True
  29. Attribute VB_PredeclaredId = False
  30. Attribute VB_Exposed = True
  31. Attribute VB_Description = "vbaccelerator Owner Draw Combo and List box control."
  32. Option Explicit
  33.  
  34. ' Styles (simple combo is not provided by this control)
  35. Public Enum EODCLStyle
  36.     ' -- Combo box styles - bit 4 not set --
  37.     ecsDropDownCombo = 0
  38.     ecsDropDownList = 2
  39.     ' -- List box styles have bit 4 set --
  40.     ecsListBox = 4
  41.     ecsListBoxMultiSelectSimple = 5
  42.     ecsListBoxMultiSelectExtended = 6
  43.     ecsListBoxChecked = 7
  44. End Enum
  45.  
  46. ' Draw modes for combo
  47. Public Enum EODCLDrawMode
  48.     ' -- Owner draw styles --
  49.     ecdNoClientDraw = 0             ' Only use default draw method
  50.     ecdDefaultDrawThenClient = 1    ' Perform default draw, but then raise client draw event
  51.     ecdClientDrawOnly = 2           ' Client does all drawing
  52.     ' -- Special styles --
  53.     ecdColourPickerWithNames = 3
  54.     ecdColourPickerNoNames = 4
  55.     ecdSysColourPicker = 5
  56.     ecdParagraphStyles = 6
  57.     ecdFontPicker = 7
  58. End Enum
  59.  
  60. ' Alignment enums
  61. Public Enum EODCLItemXAlign
  62.     eixLeft = DT_LEFT
  63.     eixCentre = DT_CENTER
  64.     eixRight = DT_RIGHT
  65. End Enum
  66. Private Const eixDT_VCENTRE = (DT_SINGLELINE Or DT_VCENTER)
  67. Private Const eixDT_BOTTOM = (DT_SINGLELINE Or DT_BOTTOM)
  68. Public Enum EODCLItemYAlign
  69.     eixTop = DT_TOP
  70.     eixVCentre = eixDT_VCENTRE
  71.     eixBottom = eixDT_BOTTOM
  72. End Enum
  73.  
  74. ' Column type enums
  75. Public Enum EODCLColType
  76.     ectTextString = 0       ' The default - draw as text, sort as text
  77.     ectTextNumber = 1       ' Convert to number during sort
  78.     ectTextDateTime = 2     ' Convert to date for sort
  79.     ectImageListIcon = 4    ' Convert to icon index in image list & assume numeric during sort
  80. End Enum
  81.  
  82. ' Whether to drop down on return or not:
  83. Private m_bExtendedUI As Boolean
  84. ' Whether sorted or not:
  85. Private m_bSorted As Boolean
  86. ' Border style (doesn't seem to be changable without heavy hacking):
  87. 'Private m_eBorderStyle As EODCLBorderStyle
  88. ' Style
  89. Private m_eStyle As EODCLStyle
  90. ' Auto complete mode for drop-down combo boxes:
  91. Private m_bDoAutoComplete As Boolean
  92. Private m_bOnlyAutoCompleteItems As Boolean
  93. Private m_bDataIsSorted As Boolean
  94.  
  95. ' Drop down width
  96. Private m_lWidth As Long
  97. Private m_hWndDropDown As Long
  98. ' Positioning drop down:
  99. Private m_bPositionDropDown As Boolean
  100. Private m_lPX As Long, m_lPY As Long
  101. Private m_lPW As Long, m_lPH As Long
  102.  
  103. ' Subclassing support:
  104. Implements ISubclass
  105. Private m_emr As EMsgResponse
  106. Private m_bSubClass As Boolean
  107. ' Whether the user is going to draw the control, or if the default
  108. ' drawing mechanism should be used:
  109. Private m_eClientDraw As EODCLDrawMode
  110. Private m_lBorderLeft As Long
  111. Private m_lBorderRight As Long
  112.  
  113. ' Handle of combo box:
  114. Private m_hWnd As Long
  115. ' Handle of edit portion if type=DropDownCombo
  116. Private m_hWndEdit As Long
  117. ' Parent of combo box:
  118. Private m_hWndparent As Long
  119. ' BackColour brush
  120. Private m_hBackBrush As Long
  121. ' Max length of chars in edit box of DropDownCombo
  122. Private m_lMaxLength As Long
  123. ' Whether we have created the font for an item:
  124. Private m_bFontNotCreated As Boolean
  125. ' Last return code
  126. Private m_lR As Long
  127. ' Last item added to combo box:
  128. Private m_lNewItem As Long
  129. ' Fonts:
  130. Private m_hFnt As Long
  131. Private m_hFntOld As Long
  132. Private m_tlF As LOGFONT
  133. Private m_hUFnt As Long
  134. Private m_tULF As LOGFONT
  135.  
  136. ' ImageList:
  137. Private m_hIml As Long
  138. Private m_lIconWidth As Long
  139. Private m_lIconHeight As Long
  140. Private m_cIL As CImageList
  141. Private m_hImlCache As Long
  142.  
  143. ' Multiple column rendering:
  144. Private m_iColCount As Integer
  145. Private m_lColWidth() As Long
  146. Private m_eCoLType() As EODCLColType
  147.  
  148. ' Other appearance:
  149. Private m_bFullRowSelect As Boolean
  150.  
  151. ' Events for this control:
  152. Public Event Click()
  153. Attribute Click.VB_Description = "Raised when the ListIndex of the combo box or list box changes."
  154. Public Event Change()
  155. Attribute Change.VB_Description = "Raised when the contents of the combo box or list box are changed."
  156. Public Event DblClick()
  157. Attribute DblClick.VB_Description = "Raised when the list box or combo box is double clicked."
  158. Public Event CloseUp()
  159. Attribute CloseUp.VB_Description = "Raised when a combo box which was dropped down is closed up.  See also the DropDown event."
  160. Public Event DropDown()
  161. Attribute DropDown.VB_Description = "Raised when the list box portion of a combo box is about to be shown."
  162. Public Event SelCancel()
  163. Attribute SelCancel.VB_Description = "Raised when the user cancels making a selection from the drop-down portion of a combo box by, for example, clicking another control."
  164. Public Event KeyDown(KeyCode As Integer, Shift As Integer)
  165. Attribute KeyDown.VB_Description = "Raised when a Key is first pressed down for an item in the control."
  166. Public Event KeyUp(KeyCode As Integer, Shift As Integer)
  167. Attribute KeyUp.VB_Description = "Raised when a key is released in the control."
  168. Public Event KeyPress(KeyAscii As Integer)
  169. Attribute KeyPress.VB_Description = "Raised when a Key is Pressed in the control."
  170. Public Event MeasureItem(Index As Long, WidthPixels As Long, HeightPixels As Long)
  171. Attribute MeasureItem.VB_Description = "Raised when the sizeof an  item needs to be determined in a list or combo box with the ecdDefaultDrawThenClient or ecdClientOnly ClientDraw styles set."
  172. Public Event DrawItem(Index As Long, hdc As Long, bSelected As Boolean, bEnabled As Boolean, LeftPixels As Long, TopPixels As Long, RightPixels As Long, BottomPixels As Long, hFntOld As Long)
  173. Attribute DrawItem.VB_Description = "Raised when an item needs to be drawn in a list or combo box with the ecdDefaultDrawThenClient or ecdClientOnly ClientDraw styles set."
  174. Public Event ODGotFocus()
  175. Attribute ODGotFocus.VB_Description = "<under development>"
  176. Public Event ODLostFocus()
  177. Attribute ODLostFocus.VB_Description = "<under development>"
  178. Public Event AutoCompleteSelection(ByVal sItem As String, ByVal lIndex As Long)
  179. Attribute AutoCompleteSelection.VB_Description = "Raised when the user clicks enter in a drop-down combo box with Auto Complete mode set."
  180.  
  181.  
  182. Property Get DoAutoComplete() As Boolean
  183. Attribute DoAutoComplete.VB_Description = "Gets/sets whether a drop-down combo will attempt to automatically complete the user's typing based on the contents of the list."
  184.     If (m_eStyle = ecsDropDownCombo) Then
  185.         DoAutoComplete = m_bDoAutoComplete
  186.     Else
  187.         DoAutoComplete = False
  188.     End If
  189. End Property
  190. Property Let DoAutoComplete(ByVal bState As Boolean)
  191.     m_bDoAutoComplete = bState
  192. End Property
  193. Public Property Get AutoCompleteListItemsOnly() As Boolean
  194. Attribute AutoCompleteListItemsOnly.VB_Description = "Gets/sets whethera drop-down combo with Auto Complete mode on should only allow selections of items in the list, or should allow any text to be entered."
  195.    AutoCompleteListItemsOnly = m_bOnlyAutoCompleteItems
  196. End Property
  197. Public Property Let AutoCompleteListItemsOnly(ByVal bState As Boolean)
  198.    m_bOnlyAutoCompleteItems = bState
  199. End Property
  200. Public Property Get AutoCompleteItemsAreSorted() As Boolean
  201. Attribute AutoCompleteItemsAreSorted.VB_Description = "Gets/sets whether the items in a drop-down combo with Auto Complete mode on should be regarded as sorted."
  202. Attribute AutoCompleteItemsAreSorted.VB_MemberFlags = "400"
  203.    AutoCompleteItemsAreSorted = m_bDataIsSorted
  204. End Property
  205. Public Property Let AutoCompleteItemsAreSorted(ByVal bState As Boolean)
  206.    m_bDataIsSorted = bState
  207. End Property
  208. Public Sub AutoCompleteKeyPress( _
  209.       ByRef iKeyAscii As Integer _
  210.    )
  211. Attribute AutoCompleteKeyPress.VB_Description = "The routine which is run in response to a KeyPress when Auto Complete mode is on."
  212. Dim sTotal As String
  213. Dim sLTotal As String
  214. Dim sUnSel As String
  215. Dim sLUnSel As String
  216. Dim lLen As Long
  217. Dim iFound As Long
  218. Dim i As Long
  219. Dim lS As Long, lW As Long
  220. Dim iStart As Long
  221. Dim sText As String
  222.  
  223.    If (iKeyAscii = vbKeyReturn) Then
  224.     If (ListIndex > -1) Then
  225.         SelStart = 0
  226.         SelLength = Len(List(ListIndex))
  227.         RaiseEvent AutoCompleteSelection(List(ListIndex), ListIndex)
  228.         Exit Sub
  229.     End If
  230.    ElseIf (iKeyAscii = vbKeyEscape) Then
  231.         Exit Sub
  232.    End If
  233.    
  234.    lS = SelStart
  235.    lW = SelLength
  236.    
  237.    If (lS > 0) Then
  238.       sUnSel = left$(Text, lS)
  239.    End If
  240.    If (iKeyAscii = 8) Then
  241.       If (Len(sUnSel) > 1) Then
  242.          sTotal = left$(sUnSel, Len(sUnSel) - 1)
  243.       Else
  244.          sUnSel = ""
  245.          iKeyAscii = 0
  246.          Text = ""
  247.          Exit Sub
  248.       End If
  249.    Else
  250.       sTotal = sUnSel & Chr$(iKeyAscii)
  251.    End If
  252.    
  253.    ' try to match the the string entered:
  254.    iFound = -1
  255.    sLTotal = LCase$(sTotal)
  256.    lLen = Len(sLTotal)
  257.    For i = 0 To ListCount - 1
  258.       If StrComp(LCase$(left$(List(i), lLen)), sLTotal) = 0 Then
  259.          iFound = i
  260.          Exit For
  261.       End If
  262.    Next i
  263.    If (iFound > -1) Then
  264.         ListIndex = iFound
  265.         'Text = List(iFound)
  266.         SelStart = Len(sTotal)
  267.         SelLength = Len(List(iFound)) - SelStart + 1
  268.         iKeyAscii = 0
  269.    Else
  270.         If (m_bOnlyAutoCompleteItems) Then
  271.             ' is there anything we can choose which has the same unmatched letters?
  272.             iStart = ListIndex
  273.             sLUnSel = LCase$(sUnSel)
  274.             lLen = Len(sLUnSel)
  275.             If (lLen > 0) Then
  276.                 If (m_bDataIsSorted) Then
  277.                     ' Its either the next one down or the first in the list:
  278.                     i = iStart + 1
  279.                     If StrComp(LCase$(left$(List(i), lLen)), sLUnSel) = 0 Then
  280.                         iFound = i
  281.                     Else
  282.                         For i = 0 To iStart - 1
  283.                             If StrComp(LCase$(left$(List(i), lLen)), sLUnSel) = 0 Then
  284.                                 iFound = i
  285.                                 Exit For
  286.                             End If
  287.                         Next i
  288.                     End If
  289.                 Else
  290.                     ' it could be anything following list index, or anything preceeding it:
  291.                     For i = iStart + 1 To ListCount - 1
  292.                         If StrComp(LCase$(left$(List(i), lLen)), sLUnSel) = 0 Then
  293.                             iFound = i
  294.                             Exit For
  295.                         End If
  296.                     Next i
  297.                     If (iFound < 0) Then
  298.                         For i = 0 To iStart - 1
  299.                             If StrComp(LCase$(left$(List(i), lLen)), sLUnSel) = 0 Then
  300.                                 iFound = i
  301.                                 Exit For
  302.                             End If
  303.                         Next i
  304.                     End If
  305.                 End If
  306.                 If (iFound > -1) Then
  307.                     ListIndex = iFound
  308.                     SelStart = lLen
  309.                     SelLength = Len(List(iFound)) - SelStart + 1
  310.                 End If
  311.             Else
  312.                 Beep
  313.             End If
  314.             iKeyAscii = 0
  315.         End If
  316.    End If
  317.    
  318. End Sub
  319.  
  320.  
  321. Property Get FullRowSelect() As Boolean
  322. Attribute FullRowSelect.VB_Description = "Gets/sets whether a selection in a list will cover the entire row or just highlight the selected item's text."
  323.     FullRowSelect = m_bFullRowSelect
  324. End Property
  325. Property Let FullRowSelect(ByVal bState As Boolean)
  326.     m_bFullRowSelect = bState
  327. End Property
  328. Property Get Columns() As Integer
  329. Attribute Columns.VB_Description = "Gets/sets the number of columns shown in a list box or combo box."
  330.     If (m_iColCount < 1) Then
  331.         Columns = 1
  332.     Else
  333.         Columns = m_iColCount
  334.     End If
  335. End Property
  336. Property Let Columns(ByVal iColCount As Integer)
  337.     If (iColCount <> m_iColCount) Then
  338.         If (iColCount < 1) Then
  339.             Erase m_lColWidth
  340.             Erase m_eCoLType
  341.             m_iColCount = 1
  342.         Else
  343.             m_iColCount = iColCount
  344.             ReDim Preserve m_lColWidth(1 To m_iColCount) As Long
  345.             ReDim Preserve m_eCoLType(1 To m_iColCount) As EODCLColType
  346.         End If
  347.         pRefreshControl
  348.     End If
  349. End Property
  350. Property Get ColWidth(ByVal iCol As Integer) As Long
  351. Attribute ColWidth.VB_Description = "Gets/sets the width of column in a list box or combo box with more than one column."
  352.     ColWidth = m_lColWidth(iCol)
  353. End Property
  354. Property Let ColWidth(ByVal iCol As Integer, ByVal lWidthPixels As Long)
  355. Dim tR As RECT
  356.     If (lWidthPixels <> m_lColWidth(iCol)) Then
  357.         m_lColWidth(iCol) = lWidthPixels
  358.         pRefreshControl
  359.     End If
  360. End Property
  361. Property Get ColType(ByVal iCol As Integer) As EODCLColType
  362. Attribute ColType.VB_Description = "Gets/sets the type of item to be displayed in a column of a combo or list box with more than one column."
  363.     ColType = m_eCoLType(iCol)
  364. End Property
  365. Property Let ColType(ByVal iCol As Integer, ByVal eColType As EODCLColType)
  366.     If (m_eCoLType(iCol) <> eColType) Then
  367.         m_eCoLType(iCol) = eColType
  368.         pRefreshControl
  369.     End If
  370. End Property
  371. Property Get InternalImageList() As CImageList
  372. Attribute InternalImageList.VB_Description = "Returns a cImageList object which used by the control to draw icons.  You can use this rather than an external image list if you wish."
  373.     ' If we haven't got an internal image list:
  374.     If m_cIL Is Nothing Then
  375.         ' Create one:
  376.         pCreateImageList
  377.     End If
  378.     ' Return the image list object
  379.     Set InternalImageList = m_cIL
  380. End Property
  381. Property Get Selected(ByVal Index As Long) As Boolean
  382. Attribute Selected.VB_Description = "Gets/sets whether an item is selected in a multi select list box."
  383. Dim lR As Long
  384.     ' Selected property is only valid for multi select
  385.     ' list boxes (always returns false otherwise):
  386.     If (m_eStyle > ecsListBox) Then
  387.         If (m_hWnd <> 0) Then
  388.             lR = SendMessageByLong(m_hWnd, LB_GETSEL, Index, 0)
  389.             Selected = (lR > 0)
  390.         End If
  391.     End If
  392. End Property
  393. Property Let Selected(ByVal Index As Long, ByVal bSelected As Boolean)
  394. Dim lS As Long
  395.     ' Selected property is only valid for multi select
  396.     ' list boxes (no effect otherwise):
  397.     If (m_eStyle > ecsListBox) Then
  398.         If (m_hWnd <> 0) Then
  399.             lS = (bSelected * -1)
  400.             Debug.Print "SetSelection"
  401.             m_lR = SendMessageByLong(m_hWnd, LB_SETSEL, lS, Index)
  402.         End If
  403.     End If
  404. End Property
  405. Public Sub SelectRange(ByVal IndexStart As Long, ByVal IndexEnd As Long, ByVal bState As Boolean)
  406. Attribute SelectRange.VB_Description = "Selects a range of text in the edit portion of a drop down combo box."
  407. Dim lS As Long, lParam As Long
  408.     ' Selecting a range is only possible for multi select
  409.     ' list boxes (no effect otherwise):
  410.     If (m_eStyle > ecsListBox) Then
  411.         If (m_hWnd <> 0) Then
  412.             If (IndexStart = IndexEnd) Then
  413.                 Selected(IndexStart) = bState
  414.             Else
  415.                 If (IndexStart > &HFFFF&) Then IndexStart = &HFFFF&
  416.                 If (IndexEnd > &HFFFF&) Then IndexEnd = &HFFFF&
  417.                 If (IndexStart > IndexEnd) Then
  418.                     lS = IndexEnd
  419.                     IndexEnd = IndexStart
  420.                     IndexStart = lS
  421.                 End If
  422.                 If (IndexEnd > ListCount - 1) Then IndexEnd = ListCount - 1
  423.                 If (IndexStart < 0) Then IndexStart = 0
  424.                 lS = (bState * -1)
  425.                 lParam = IndexStart + (IndexEnd * &H10000)
  426.                 m_lR = SendMessageByLong(m_hWnd, LB_SELITEMRANGE, lS, lParam)
  427.             End If
  428.         End If
  429.     End If
  430. End Sub
  431. Public Sub SetDefaultDrawBorder(ByVal LeftPixels As Long, ByVal RightPixels As Long)
  432. Attribute SetDefaultDrawBorder.VB_Description = "Sets the offset position for any drawing in the list box portion of the control from the borders when in default draw mode."
  433.     ' When in default draw mode, any drawing in the
  434.     ' list box portion of the control will be
  435.     ' offset from the borders by these amounts:
  436.     m_lBorderLeft = LeftPixels
  437.     m_lBorderRight = RightPixels
  438. End Sub
  439. Property Get Text() As String
  440. Attribute Text.VB_Description = "Gets/sets the text in the edit portion of a drop-down combo box, or returns the text of the first selected item in other types."
  441. Dim lR As Long
  442. Dim sText As String
  443.     ' Returns either the text in the EditBox portion of a
  444.     ' drop down combo or the text of the (first) selected
  445.     ' list item:
  446.     If (m_hWnd <> 0) Then
  447.         If (m_eStyle = ecsDropDownCombo) Then
  448.             lR = SendMessageByLong(m_hWnd, WM_GETTEXTLENGTH, 0, 0)
  449.             If (lR > 0) Then
  450.                 sText = String$(lR + 1, Chr$(0))
  451.                 lR = SendMessageByString(m_hWnd, WM_GETTEXT, (lR + 1), sText)
  452.                 If (lR > 0) Then
  453.                     Text = left$(sText, lR)
  454.                 End If
  455.             End If
  456.         Else
  457.             If (ListIndex > -1) Then
  458.                 Text = List(ListIndex)
  459.             End If
  460.         End If
  461.     End If
  462. End Property
  463. Property Let Text(ByVal sText As String)
  464.     ' Can only set the text in a drop down combo box:
  465.     If (m_eStyle = ecsDropDownCombo) Then
  466.         SendMessageByString m_hWnd, WM_SETTEXT, 0, sText & Chr$(0)
  467.     Else
  468.         Err.Raise 383, "OwnerDrawCombo." & App.EXEName
  469.     End If
  470. End Property
  471. Property Get MaxLength() As Long
  472. Attribute MaxLength.VB_Description = "Gets/sets the maximum amount of text which can be entered into the edit portion of a drop-down combo box."
  473.     ' Same as MaxLength property of a Text control.  Only
  474.     ' valid for drop down combo boxes:
  475.     If (m_eStyle = ecsDropDownCombo) Then
  476.         MaxLength = m_lMaxLength
  477.     End If
  478. End Property
  479. Property Let MaxLength(ByVal lLength As Long)
  480.     ' Same as MaxLength property of a Text control.  Only
  481.     ' valid for drop down combo boxes:
  482.     If (m_eStyle = ecsDropDownCombo) Then
  483.         ' Don't be silly:
  484.         If (lLength > 30000&) Or (lLength <= 0) Then lLength = 30000&
  485.         ' Set:
  486.         m_lMaxLength = lLength
  487.         SendMessageByLong m_hWnd, CB_LIMITTEXT, lLength, 0
  488.     End If
  489. End Property
  490. Private Sub pGetSelStartEnd(lStart As Long, lENd As Long)
  491. Dim lParam As Long
  492.     ' Get the start and end of the selection in the edit
  493.     ' box portion of a drop down combo box:
  494.     If (m_hWnd <> 0) Then
  495.         lParam = SendMessageByLong(m_hWnd, CB_GETEDITSEL, lStart, lENd)
  496.         gGetHiWordLoWord lParam, lENd, lStart
  497.     End If
  498. End Sub
  499. Private Sub pSetSelStartEnd(ByVal lStart As Long, ByVal lENd As Long)
  500. Dim lParam As Long
  501.     ' Set the start and end of the selection in the edit
  502.     ' box portion of a drop down combo box:
  503.     If (m_hWnd <> 0) Then
  504.         If (lStart > &HFFFF&) Then lStart = &HFFFF&
  505.         If (lENd > &HFFFF&) Then lENd = &HFFFF&
  506.         lParam = lStart + lENd * &H10000
  507.         SendMessageByLong m_hWnd, CB_SETEDITSEL, 0, lParam
  508.     End If
  509. End Sub
  510. Property Get SelStart() As Long
  511. Attribute SelStart.VB_Description = "Gets the start of the selection in the edit portion of a drop down combo box."
  512. Attribute SelStart.VB_MemberFlags = "400"
  513. Dim lStart As Long, lENd As Long
  514.     ' Return the start of the selected text in the edit
  515.     ' box portion of a dropdown combo:
  516.     If (m_eStyle = ecsDropDownCombo) Then
  517.         pGetSelStartEnd lStart, lENd
  518.         SelStart = lStart
  519.     Else
  520.         Err.Raise 383, "OwnerDrawCombo." & App.EXEName
  521.     End If
  522. End Property
  523. Property Let SelStart(ByVal lStart As Long)
  524. Dim lOStart As Long, lENd As Long
  525.     ' Set the start of the selected text in the edit
  526.     ' box portion of a dropdown combo:
  527.     If (m_eStyle = ecsDropDownCombo) Then
  528.         pGetSelStartEnd lOStart, lENd
  529.         If (lStart <> lOStart) Then
  530.             pSetSelStartEnd lStart, lENd
  531.         End If
  532.     Else
  533.         Err.Raise 383, "OwnerDrawCombo." & App.EXEName
  534.     End If
  535. End Property
  536. Property Get SelLength() As Long
  537. Attribute SelLength.VB_Description = "Gets the length of the selection in the edit portion of a drop down combo box."
  538. Attribute SelLength.VB_MemberFlags = "400"
  539. Dim lStart As Long, lENd As Long
  540.     ' Return the length of the selected text in the edit
  541.     ' box portion of a dropdown combo:
  542.     If (m_eStyle = ecsDropDownCombo) Then
  543.         pGetSelStartEnd lStart, lENd
  544.         SelLength = lENd - lStart
  545.     Else
  546.         Err.Raise 383, "OwnerDrawCombo." & App.EXEName
  547.     End If
  548. End Property
  549. Property Let SelLength(ByVal lLength As Long)
  550. Dim lStart As Long, lENd As Long
  551.     ' Set the length of the selected text in the edit
  552.     ' box portion of a dropdown combo:
  553.     If (m_eStyle = ecsDropDownCombo) Then
  554.         pGetSelStartEnd lStart, lENd
  555.         If (lENd - lStart <> lLength) Then
  556.             pSetSelStartEnd lStart, lStart + lLength
  557.         End If
  558.     Else
  559.         Err.Raise 383, "OwnerDrawCombo." & App.EXEName
  560.     End If
  561. End Property
  562. Property Get SelText() As String
  563. Attribute SelText.VB_Description = "Gets the selected text from the edit portion of a drop down combo box."
  564.     ' Return the selected text from the edit
  565.     ' box portion of a dropdown combo:
  566.     If (m_eStyle = ecsDropDownCombo) Then
  567.         Dim sText As String
  568.         Dim lStart As Long, lENd As Long
  569.         
  570.         pGetSelStartEnd lStart, lENd
  571.         sText = Text
  572.         If (lENd > 0) And Len(sText) > 0 Then
  573.             If (lStart <= 0) Then
  574.                 lStart = 1
  575.             End If
  576.             lENd = lENd + 1
  577.             If (lENd > Len(sText)) Then lENd = Len(sText)
  578.             SelText = Mid$(sText, lStart, (lENd - lStart))
  579.         End If
  580.     Else
  581.         SelText = Text
  582.     End If
  583. End Property
  584. Property Get hwnd() As Long
  585. Attribute hwnd.VB_Description = "Gets the hWnd of the combo box or list box control.  If you want the hWnd of the control itself, find the parent of this handle."
  586.     ' Return the hWnd of the Combo or List.
  587.     hwnd = m_hWnd
  588. End Property
  589. Property Get hWndEdit() As Long
  590. Attribute hWndEdit.VB_Description = "Gets the hWnd of the edit box in a drop-down combo control."
  591.     hWndEdit = m_hWndEdit
  592. End Property
  593.  
  594. Property Let ImageList(ByRef vThis As Variant)
  595. Attribute ImageList.VB_Description = "Sets the image list to be used to draw icons in the control.  Can either be set to a Visual Basic Image List control or a hImageList handle to an API image list."
  596. Dim tR As RECT
  597.     ' Set the ImageList handle property either from a VB
  598.     ' image list or directly:
  599.     m_hIml = 0
  600.     If VarType(vThis) = vbObject Then
  601.         ' Assume VB ImageList control.  Note that unless
  602.         ' some call has been made to an object within a
  603.         ' VB ImageList the image list itself is not
  604.         ' created.  Therefore hImageList returns error. So
  605.         ' ensure that the ImageList has been initialised by
  606.         ' drawing into nowhere:
  607.         On Error Resume Next
  608.         ' Get the image list initialised..
  609.         vThis.ListImages(1).Draw 0, 0, 0, 1
  610.         m_hImlCache = vThis.hImageList
  611.         If (Err.Number <> 0) Then
  612.             m_hImlCache = 0
  613.         End If
  614.         On Error GoTo 0
  615.     ElseIf VarType(vThis) = vbLong Then
  616.         ' Assume ImageList handle:
  617.         m_hImlCache = vThis
  618.     Else
  619.         Err.Raise vbObjectError + 1049, "OwnerDrawCombo." & App.EXEName, "ImageList property expects ImageList object or long hImageList handle."
  620.     End If
  621.     
  622.     If (m_eClientDraw = ecdParagraphStyles) Or (m_eClientDraw = ecdFontPicker) Then
  623.         ' Do not change m_hIml yet, wait until style changes away from
  624.         ' these styles.
  625.     Else
  626.         m_hIml = m_hImlCache
  627.     End If
  628.     If (m_hImlCache <> 0) Then
  629.         ImageList_GetImageRect m_hImlCache, 0, tR
  630.         m_lIconWidth = tR.Right - tR.left
  631.         m_lIconHeight = tR.Bottom - tR.tOp
  632.     End If
  633.  
  634. End Property
  635.  
  636. Property Get ItemIcon( _
  637.         ByVal lListIndex As Long _
  638.     ) As Long
  639. Attribute ItemIcon.VB_Description = "Gets/sets the icon to draw next to an item in the control."
  640. Dim tLI As ICONLISTBOXITEMINFO
  641. Dim hMem As Long
  642.     ' Returns the icon for a list item:
  643.     hMem = plGetItemData(lListIndex)
  644.     pGetItemInfo hMem, tLI
  645.     ItemIcon = tLI.lIconIndex
  646.     
  647. End Property
  648. Property Let ItemIcon( _
  649.         ByVal lListIndex As Long, _
  650.         ByVal lIconIndex As Long _
  651.     )
  652. Dim tLI As ICONLISTBOXITEMINFO
  653. Dim hMem As Long
  654.     ' Sets the icon for a list item:
  655.     hMem = plGetItemData(lListIndex)
  656.     pGetItemInfo hMem, tLI
  657.     tLI.lIconIndex = lIconIndex
  658.     pWriteItemInfo hMem, tLI
  659.     pRedrawItem lListIndex
  660. End Property
  661. Property Get ItemIndent( _
  662.         ByVal lIndex As Long _
  663.     ) As Long
  664. Attribute ItemIndent.VB_Description = "Gets/sets the number of pixels to an indent an item in the control."
  665. Dim tLI As ICONLISTBOXITEMINFO
  666. Dim hMem As Long
  667.     ' Returns the indent for a list item:
  668.     hMem = plGetItemData(lIndex)
  669.     pGetItemInfo hMem, tLI
  670.     ItemIndent = tLI.lIndentSize
  671. End Property
  672. Property Let ItemIndent( _
  673.         ByVal lIndex As Long, _
  674.         ByVal lIndentSize As Long _
  675.     )
  676. Dim tLI As ICONLISTBOXITEMINFO
  677. Dim hMem As Long
  678.     ' Sets the indent for a list item:
  679.     hMem = plGetItemData(lIndex)
  680.     pGetItemInfo hMem, tLI
  681.     tLI.lIndentSize = lIndentSize
  682.     pWriteItemInfo hMem, tLI
  683.     pRedrawItem lIndex
  684. End Property
  685. Property Get ItemBackColor( _
  686.         ByVal lIndex As Long _
  687.     ) As OLE_COLOR
  688. Attribute ItemBackColor.VB_Description = "Gets/sets the back color of an item in the control."
  689. Dim tLI As ICONLISTBOXITEMINFO
  690. Dim hMem As Long
  691.     ' Returns the back colour for an item:
  692.     hMem = plGetItemData(lIndex)
  693.     pGetItemInfo hMem, tLI
  694.     If (tLI.lBackColour = -1) Then
  695.         ItemBackColor = UserControl.BackColor
  696.     Else
  697.         ItemBackColor = tLI.lBackColour
  698.     End If
  699. End Property
  700. Property Let ItemBackColor( _
  701.         ByVal lIndex As Long, _
  702.         ByVal lBackColour As OLE_COLOR _
  703.     )
  704. Dim tLI As ICONLISTBOXITEMINFO
  705. Dim hMem As Long
  706.     ' Sets the back colour for an item.  Set to -1 for default:
  707.     hMem = plGetItemData(lIndex)
  708.     pGetItemInfo hMem, tLI
  709.     tLI.lBackColour = lBackColour
  710.     pWriteItemInfo hMem, tLI
  711.     pRedrawItem lIndex
  712. End Property
  713. Property Get ItemXAlign( _
  714.         ByVal lIndex As Long _
  715.     ) As EODCLItemXAlign
  716. Attribute ItemXAlign.VB_Description = "Gets/sets the X Alignment of text drawn for an item in the control."
  717. Dim tLI As ICONLISTBOXITEMINFO
  718. Dim hMem As Long
  719.     ' Returns the horizontal text alignment for an item:
  720.     hMem = plGetItemData(lIndex)
  721.     pGetItemInfo hMem, tLI
  722.     ItemXAlign = tLI.lTextAlignX
  723. End Property
  724. Property Let ItemXAlign( _
  725.         ByVal lIndex As Long, _
  726.         ByVal eXAlign As EODCLItemXAlign _
  727.     )
  728. Dim tLI As ICONLISTBOXITEMINFO
  729. Dim hMem As Long
  730.     ' Sets the horizontal text alignment for an item:
  731.     hMem = plGetItemData(lIndex)
  732.     pGetItemInfo hMem, tLI
  733.     tLI.lTextAlignX = eXAlign
  734.     pWriteItemInfo hMem, tLI
  735.     pRedrawItem lIndex
  736. End Property
  737. Property Get ItemYAlign( _
  738.         ByVal lIndex As Long _
  739.     ) As EODCLItemYAlign
  740. Attribute ItemYAlign.VB_Description = "Gets/sets the Y Alignment of text drawn for an item in the control."
  741. Dim tLI As ICONLISTBOXITEMINFO
  742. Dim hMem As Long
  743.     ' Returns the vertical text alignment for an item:
  744.     hMem = plGetItemData(lIndex)
  745.     pGetItemInfo hMem, tLI
  746.     ItemYAlign = tLI.lTextAlignY
  747. End Property
  748. Property Let ItemYAlign( _
  749.         ByVal lIndex As Long, _
  750.         ByVal eYAlign As EODCLItemYAlign _
  751.     )
  752. Dim tLI As ICONLISTBOXITEMINFO
  753. Dim hMem As Long
  754.     ' Sets the vertical text alignment for an item:
  755.     hMem = plGetItemData(lIndex)
  756.     pGetItemInfo hMem, tLI
  757.     tLI.lTextAlignY = eYAlign
  758.     pWriteItemInfo hMem, tLI
  759.     pRedrawItem lIndex
  760. End Property
  761. Property Get ItemExtraData( _
  762.         ByVal lIndex As Long _
  763.     ) As Long
  764. Attribute ItemExtraData.VB_Description = "Gets/sets an additional long value associated withf an item in the control."
  765. Dim tLI As ICONLISTBOXITEMINFO
  766. Dim hMem As Long
  767.     ' Returns an extra long stored with an item:
  768.     hMem = plGetItemData(lIndex)
  769.     pGetItemInfo hMem, tLI
  770.     ItemExtraData = tLI.lExtraData
  771.     
  772. End Property
  773. Property Let ItemExtraData( _
  774.         ByVal lIndex As Long, _
  775.         ByVal lExtraData As Long _
  776.     )
  777. Dim tLI As ICONLISTBOXITEMINFO
  778. Dim hMem As Long
  779.     ' Sets an extra long stored with an item:
  780.     hMem = plGetItemData(lIndex)
  781.     pGetItemInfo hMem, tLI
  782.     tLI.lExtraData = lExtraData
  783.     pWriteItemInfo hMem, tLI
  784. End Property
  785.     
  786. Property Get ItemForeColor( _
  787.         ByVal lIndex As Long _
  788.     ) As OLE_COLOR
  789. Attribute ItemForeColor.VB_Description = "Gets/sets the fore color of an item in the control."
  790. Dim tLI As ICONLISTBOXITEMINFO
  791. Dim hMem As Long
  792.     ' Returns the fore colour for an item:
  793.     hMem = plGetItemData(lIndex)
  794.     pGetItemInfo hMem, tLI
  795.     If (tLI.lForeColour = -1) Then
  796.         ItemForeColor = UserControl.ForeColor
  797.     Else
  798.         ItemForeColor = tLI.lForeColour
  799.     End If
  800. End Property
  801. Property Let ItemForeColor( _
  802.         ByVal lIndex As Long, _
  803.         ByVal lForeColour As OLE_COLOR _
  804.     )
  805. Dim tLI As ICONLISTBOXITEMINFO
  806. Dim hMem As Long
  807.     ' Sets the fore colour for an item:
  808.     hMem = plGetItemData(lIndex)
  809.     pGetItemInfo hMem, tLI
  810.     tLI.lForeColour = lForeColour
  811.     pWriteItemInfo hMem, tLI
  812.     pRedrawItem lIndex
  813. End Property
  814. Public Sub AddItemAndData( _
  815.         ByVal sItem As String, _
  816.         Optional ByVal lIconIndex As Long = -1, _
  817.         Optional ByVal lIndent As Long = 0, _
  818.         Optional ByVal lForeColour As OLE_COLOR = -1, _
  819.         Optional ByVal lBackColour As OLE_COLOR = -1, _
  820.         Optional ByVal lItemData As Long = 0, _
  821.         Optional ByVal lExtraData As Long = 0, _
  822.         Optional ByVal lHeight As Long = -1, _
  823.         Optional ByVal eTextXAlign As EODCLItemXAlign = eixLeft, _
  824.         Optional ByVal eTextYAlign As EODCLItemYAlign = eixTop, _
  825.         Optional ByRef fntThis As StdFont = Nothing _
  826.     )
  827. Attribute AddItemAndData.VB_Description = "Adds an item to the combo or list box and also allows font, colours, formatting or icons to be set at the same time."
  828. Dim wMsg As Long
  829. Dim tLI As ICONLISTBOXITEMINFO
  830. Dim hMem As Long
  831.  
  832.     ' Same as AddItem, but the extended properties can be
  833.     ' set at the same time.  Quicker!
  834.  
  835.     ' Determine type of control:
  836.     If (m_eStyle And ecsListBox) = ecsListBox Then
  837.         wMsg = LB_ADDSTRING
  838.     Else
  839.         wMsg = CB_ADDSTRING
  840.     End If
  841.     
  842.     ' Add the text item:
  843.     m_lR = SendMessageByString(m_hWnd, wMsg, 0, sItem)
  844.     
  845.     ' If successful:
  846.     If (m_lR <> CB_ERR) Then
  847.         ' Store the index of the item just added for the
  848.         ' NewIndex property:
  849.         m_lNewItem = m_lR
  850.         
  851.         ' Allocate the global memory to store the extended
  852.         ' properties for this item:
  853.         hMem = GlobalAlloc(GPTR, Len(tLI))
  854.         
  855.         ' Store the extended properties:
  856.         tLI.lBackColour = lBackColour
  857.         tLI.lForeColour = lForeColour
  858.         tLI.lIndentSize = lIndent
  859.         tLI.lIconIndex = lIconIndex
  860.         tLI.lItemData = lItemData
  861.         tLI.lExtraData = lExtraData
  862.         tLI.lTextAlignX = eTextXAlign
  863.         tLI.lTextAlignY = eTextYAlign
  864.         
  865.         If (lHeight < 0) Then
  866.             ' Use default
  867.             tLI.lItemHeight = 16
  868.         Else
  869.             tLI.lItemHeight = lHeight
  870.         End If
  871.                 
  872.         ' If the item height is specified, we need to send
  873.         ' this message to ensure the height is actually set:
  874.         If (m_eStyle And ecsListBox) = ecsListBox Then
  875.             wMsg = LB_SETITEMHEIGHT
  876.         Else
  877.             wMsg = CB_SETITEMHEIGHT
  878.         End If
  879.         SendMessageByLong m_hWnd, wMsg, m_lR, tLI.lItemHeight
  880.  
  881.         ' If a font specified, then store the LOGFONT structure
  882.         ' for it:
  883.         If Not (fntThis Is Nothing) Then
  884.             pOLEFontToLogFont fntThis, UserControl.hdc, tLI.tLF
  885.             tLI.dFontSize = fntThis.Size
  886.         End If
  887.         
  888.         ' Write this item into the global memory block:
  889.         pWriteItemInfo hMem, tLI
  890.         
  891.         ' Attach the memory block to the list item by setting
  892.         ' the item data to the memory block pointer:
  893.         If (m_eStyle And ecsListBox) = ecsListBox Then
  894.             wMsg = LB_SETITEMDATA
  895.         Else
  896.             wMsg = CB_SETITEMDATA
  897.         End If
  898.         m_lR = SendMessageByLong(m_hWnd, wMsg, m_lNewItem, hMem)
  899.                 
  900.     End If
  901.     
  902. End Sub
  903. Public Sub AddItem(ByVal sItem As String)
  904. Attribute AddItem.VB_Description = "Adds an item to the combo or list  box (same as VB List box AddItem method).  Use AddItemWithData for a quicker method if you also want to set icons, formatting, colours etc for the item."
  905.     ' AddItem method same as VB AddItem for a ListBox
  906.     ' or ComboBox.
  907.     
  908.     ' Just call AddItemWithData with all the defaults set:
  909.     AddItemAndData sItem
  910.  
  911. End Sub
  912. Property Get NewIndex() As Long
  913. Attribute NewIndex.VB_Description = "Gets the index of the latest item to be added to the control."
  914.     ' Returns the last index added to the control:
  915.     NewIndex = m_lNewItem
  916. End Property
  917.  
  918. Property Let ItemUnderLine( _
  919.         ByVal lIndex As Long, _
  920.         ByVal bUnderLineItem As Boolean _
  921.     )
  922. Attribute ItemUnderLine.VB_Description = "Gets/sets whether a separator line should be drawn below an item in the control."
  923. Dim tLI As ICONLISTBOXITEMINFO
  924. Dim hMem As Long
  925.     hMem = plGetItemData(lIndex)
  926.     pGetItemInfo hMem, tLI
  927.     tLI.bUnderLineItem = bUnderLineItem
  928.     pWriteItemInfo hMem, tLI
  929. End Property
  930. Property Get ItemUnderLine( _
  931.         ByVal lIndex As Long _
  932.     ) As Boolean
  933. Dim tLI As ICONLISTBOXITEMINFO
  934. Dim hMem As Long
  935.     hMem = plGetItemData(lIndex)
  936.     pGetItemInfo hMem, tLI
  937.     ItemUnderLine = tLI.bUnderLineItem
  938. End Property
  939. Property Let ItemFont( _
  940.         ByVal lIndex As Long, _
  941.         fntThis As StdFont _
  942.     )
  943. Attribute ItemFont.VB_Description = "Gets/sets the font with which to draw an item in the control."
  944. Dim tLI As ICONLISTBOXITEMINFO
  945. Dim hMem As Long
  946. Dim i As Long
  947.     hMem = plGetItemData(lIndex)
  948.     pGetItemInfo hMem, tLI
  949.     If (fntThis Is Nothing) Then
  950.         ' Reset font to default:
  951.         For i = 0 To 32
  952.             tLI.tLF.lfFaceName(i) = 0
  953.         Next i
  954.     Else
  955.         ' Store the LOGFONT structure for this font:
  956.         pOLEFontToLogFont fntThis, UserControl.hdc, tLI.tLF
  957.     End If
  958.     tLI.dFontSize = fntThis.Size
  959.     pWriteItemInfo hMem, tLI
  960.     pRedrawItem lIndex
  961. End Property
  962. Property Get ItemFont( _
  963.         ByVal lIndex As Long _
  964.     ) As StdFont
  965. Dim tLI As ICONLISTBOXITEMINFO
  966. Dim hMem As Long
  967. Dim fntThis As New StdFont
  968.     hMem = plGetItemData(lIndex)
  969.     pGetItemInfo hMem, tLI
  970.     If (tLI.tLF.lfFaceName(0) = 0) Then
  971.         Set ItemFont = UserControl.Font
  972.     Else
  973.         fntThis.Name = StrConv(tLI.tLF.lfFaceName, vbUnicode)
  974.         fntThis.Size = tLI.dFontSize
  975.         fntThis.Bold = (tLI.tLF.lfWeight = FW_BOLD)
  976.         fntThis.Italic = (tLI.tLF.lfItalic <> 0)
  977.         fntThis.Underline = (tLI.tLF.lfUnderline <> 0)
  978.         fntThis.Strikethrough = (tLI.tLF.lfStrikeOut <> 0)
  979.         Set ItemFont = fntThis
  980.     End If
  981. End Property
  982. Property Let ItemOverLine( _
  983.         ByVal lIndex As Long, _
  984.         ByVal bOverLineItem As Boolean _
  985.     )
  986. Attribute ItemOverLine.VB_Description = "Gets/sets whether a separator line should be drawn above an item in the control."
  987. Dim tLI As ICONLISTBOXITEMINFO
  988. Dim hMem As Long
  989.     hMem = plGetItemData(lIndex)
  990.     pGetItemInfo hMem, tLI
  991.     tLI.bOverLineItem = bOverLineItem
  992.     pWriteItemInfo hMem, tLI
  993.  
  994. End Property
  995. Property Get ItemOverLine( _
  996.         ByVal lIndex As Long _
  997.     ) As Boolean
  998. Dim tLI As ICONLISTBOXITEMINFO
  999. Dim hMem As Long
  1000.     hMem = plGetItemData(lIndex)
  1001.     pGetItemInfo hMem, tLI
  1002.     ItemOverLine = tLI.bOverLineItem
  1003.  
  1004. End Property
  1005. Property Get List(ByVal lIndex As Long) As String
  1006. Attribute List.VB_Description = "Gets/sets the text of a list item in the control."
  1007. Dim sBuf As String
  1008. Dim lLen As Long
  1009. Dim wMsg As Long
  1010.     If (m_eStyle And ecsListBox) = ecsListBox Then
  1011.         wMsg = LB_GETTEXTLEN
  1012.     Else
  1013.         wMsg = CB_GETLBTEXTLEN
  1014.     End If
  1015.     m_lR = SendMessageByLong(m_hWnd, wMsg, lIndex, 0)
  1016.     lLen = m_lR
  1017.     If (lLen <> CB_ERR) Then
  1018.         sBuf = String$((lLen), 0)
  1019.         If (m_eStyle And ecsListBox) = ecsListBox Then
  1020.             wMsg = LB_GETTEXT
  1021.         Else
  1022.             wMsg = CB_GETLBTEXT
  1023.         End If
  1024.         m_lR = SendMessageByString(m_hWnd, wMsg, lIndex, sBuf)
  1025.         If (m_lR <> CB_ERR) Then
  1026.             List = sBuf
  1027.         End If
  1028.     End If
  1029. End Property
  1030. Property Let List( _
  1031.         ByVal lIndex As Long, _
  1032.         ByVal sItem As String _
  1033.     )
  1034. Dim hMem As Long
  1035. Dim wMsg As Long
  1036. Dim tLI As ICONLISTBOXITEMINFO
  1037.     If (lIndex < ListCount And lIndex > -1) Then
  1038.         ' Remove the existing string at this index:
  1039.         ' First get the memory block for the item
  1040.         hMem = plGetItemData(lIndex)
  1041.         pGetItemInfo hMem, tLI
  1042.         RemoveItem lIndex
  1043.         InsertItem sItem, lIndex
  1044.         hMem = plGetItemData(lIndex)
  1045.         pWriteItemInfo hMem, tLI
  1046.         If (tLI.lItemHeight > 0) Then
  1047.             If (m_eStyle And ecsListBox) = ecsListBox Then
  1048.                 wMsg = LB_SETITEMHEIGHT
  1049.             Else
  1050.                 wMsg = CB_SETITEMHEIGHT
  1051.             End If
  1052.             SendMessageByLong m_hWnd, wMsg, lIndex, tLI.lItemHeight
  1053.         End If
  1054.     End If
  1055. End Property
  1056. Public Sub InsertItemAndData( _
  1057.         ByVal sItem As String, _
  1058.         ByVal lIndex As Long, _
  1059.         Optional ByVal lIconIndex As Long = -1, _
  1060.         Optional ByVal lIndent As Long = 0, _
  1061.         Optional ByVal lForeColour As OLE_COLOR = -1, _
  1062.         Optional ByVal lBackColour As OLE_COLOR = -1, _
  1063.         Optional ByVal lItemData As Long = 0, _
  1064.         Optional ByVal lExtraData As Long = 0, _
  1065.         Optional ByVal lHeight As Long = 0, _
  1066.         Optional ByVal eTextXAlign As EODCLItemXAlign = eixLeft, _
  1067.         Optional ByVal eTextYAlign As EODCLItemYAlign = eixTop, _
  1068.         Optional ByRef fntThis As StdFont = Nothing _
  1069.     )
  1070. Attribute InsertItemAndData.VB_Description = "Inserts an item to the combo or list box and also allows font, colours, formatting or icons to be set at the same time."
  1071. Dim wMsg As Long
  1072. Dim tLI As ICONLISTBOXITEMINFO
  1073. Dim hMem As Long
  1074.     
  1075.     If (m_eStyle And ecsListBox) = ecsListBox Then
  1076.         wMsg = LB_INSERTSTRING
  1077.     Else
  1078.         wMsg = CB_INSERTSTRING
  1079.     End If
  1080.     m_lR = SendMessageByString(m_hWnd, wMsg, lIndex, sItem)
  1081.     If (m_lR <> CB_ERR) Then
  1082.         m_lNewItem = m_lR
  1083.         ' Allocate the global memory for this item:
  1084.         hMem = GlobalAlloc(GPTR, Len(tLI))
  1085.         tLI.lBackColour = lBackColour
  1086.         tLI.lForeColour = lForeColour
  1087.         tLI.lIndentSize = lIndent
  1088.         tLI.lIconIndex = lIconIndex
  1089.         tLI.lItemData = lItemData
  1090.         tLI.lExtraData = lExtraData
  1091.         tLI.lTextAlignX = eTextXAlign
  1092.         tLI.lTextAlignY = eTextYAlign
  1093.         If (lHeight < 0) Then
  1094.             ' Use default
  1095.             tLI.lItemHeight = 16
  1096.         Else
  1097.             tLI.lItemHeight = lHeight
  1098.         End If
  1099.         If (m_eStyle And ecsListBox) = ecsListBox Then
  1100.             wMsg = LB_SETITEMHEIGHT
  1101.         Else
  1102.             wMsg = CB_SETITEMHEIGHT
  1103.         End If
  1104.         SendMessageByLong m_hWnd, wMsg, m_lR, tLI.lItemHeight
  1105.         If Not (fntThis Is Nothing) Then
  1106.             pOLEFontToLogFont fntThis, UserControl.hdc, tLI.tLF
  1107.             tLI.dFontSize = fntThis.Size
  1108.         End If
  1109.         
  1110.         pWriteItemInfo hMem, tLI
  1111.         ' Attach this item to the list item:
  1112.         If (m_eStyle And ecsListBox) = ecsListBox Then
  1113.             wMsg = LB_SETITEMDATA
  1114.         Else
  1115.             wMsg = CB_SETITEMDATA
  1116.         End If
  1117.         m_lR = SendMessageByLong(m_hWnd, wMsg, m_lNewItem, hMem)
  1118.     End If
  1119.         
  1120. End Sub
  1121.  
  1122. Public Sub InsertItem( _
  1123.         ByVal sItem As String, _
  1124.         ByVal lIndex As Long _
  1125.     )
  1126. Attribute InsertItem.VB_Description = "Inserts an item in the list items of a combo or list box.   Use InsertItemWithData for a quicker method if you also want to set icons, formatting, colours etc for the item."
  1127. Dim wMsg As Long
  1128. Dim tLI As ICONLISTBOXITEMINFO
  1129. Dim hMem As Long
  1130.  
  1131.     If (m_eStyle And ecsListBox) = ecsListBox Then
  1132.         wMsg = LB_INSERTSTRING
  1133.     Else
  1134.         wMsg = CB_INSERTSTRING
  1135.     End If
  1136.     m_lR = SendMessageByString(m_hWnd, wMsg, lIndex, sItem)
  1137.     If (m_lR <> CB_ERR) Then
  1138.         m_lNewItem = m_lR
  1139.         ' Allocate the global memory for this item:
  1140.         hMem = GlobalAlloc(GPTR, Len(tLI))
  1141.         tLI.lBackColour = UserControl.BackColor
  1142.         tLI.lForeColour = UserControl.ForeColor
  1143.         tLI.lIconIndex = -1
  1144.         pWriteItemInfo hMem, tLI
  1145.         ' Attach this item to the list item:
  1146.         If (m_eStyle And ecsListBox) = ecsListBox Then
  1147.             wMsg = LB_SETITEMDATA
  1148.         Else
  1149.             wMsg = CB_SETITEMDATA
  1150.         End If
  1151.         m_lR = SendMessageByLong(m_hWnd, wMsg, m_lNewItem, hMem)
  1152.     End If
  1153. End Sub
  1154. Public Sub RemoveItem( _
  1155.         ByVal lIndex As Long _
  1156.     )
  1157. Attribute RemoveItem.VB_Description = "Removes an item from the control's list."
  1158. Dim wMsg As Long
  1159. Dim hMem As Long
  1160.  
  1161.     If lIndex < ListCount And lIndex > -1 Then
  1162.         ' Firstly remove the memory associated with this index:
  1163.         hMem = plGetItemData(lIndex)
  1164.         GlobalFree hMem
  1165.         ' Now remove the string:
  1166.         If (m_eStyle And ecsListBox) = ecsListBox Then
  1167.             wMsg = LB_DELETESTRING
  1168.         Else
  1169.             wMsg = CB_DELETESTRING
  1170.         End If
  1171.         m_lR = SendMessageByLong(m_hWnd, wMsg, lIndex, 0)
  1172.         If (m_lR = CB_ERR) Then
  1173.             ' Raise error
  1174.             Debug.Print "RemoveItem: Error!"
  1175.         End If
  1176.     Else
  1177.         ' Raise error...
  1178.         Debug.Print "RemoveItem: Error!"
  1179.     End If
  1180. End Sub
  1181. Property Get ListIndex() As Long
  1182. Attribute ListIndex.VB_Description = "Gets/sets the currently selected item in the list.  In multi-select list boxes, this returns the first selected item.  Use the Selected property instead."
  1183. Attribute ListIndex.VB_MemberFlags = "400"
  1184. Dim wMsg As Long
  1185.     If (m_eStyle And ecsListBox) = ecsListBox Then
  1186.         wMsg = LB_GETCURSEL
  1187.     Else
  1188.         wMsg = CB_GETCURSEL
  1189.     End If
  1190.     m_lR = SendMessageByLong(m_hWnd, wMsg, 0, 0)
  1191.     ListIndex = m_lR
  1192. End Property
  1193. Property Let ListIndex( _
  1194.         ByVal lIndex As Long _
  1195.     )
  1196. Dim wMsg As Long
  1197.     If (m_eStyle And ecsListBox) = ecsListBox Then
  1198.         wMsg = LB_SETCURSEL
  1199.     Else
  1200.         wMsg = CB_SETCURSEL
  1201.     End If
  1202.     m_lR = SendMessageByLong(m_hWnd, wMsg, lIndex, 0)
  1203.     If (m_lR = CB_ERR) And (lIndex <> -1) Then
  1204.         Err.Raise 381, App.EXEName & ".ODCboLst"
  1205.     Else
  1206.         RaiseEvent Click
  1207.     End If
  1208.  
  1209.     
  1210.     If (m_eClientDraw = ecdFontPicker) Then
  1211.         ' Here we cache the fonts
  1212.     End If
  1213.  
  1214. End Property
  1215. Private Sub pGetItemInfo( _
  1216.         ByVal hMem As Long, _
  1217.         ByRef tLI As ICONLISTBOXITEMINFO _
  1218.     )
  1219. Dim lPtr As Long
  1220.     If (hMem <> 0) And (hMem <> CB_ERR) Then
  1221.         ' Get a pointer to the memory block
  1222.         ' pointed to by hMem:
  1223.         lPtr = GlobalLock(hMem)
  1224.         ' Copy the memory into tLI
  1225.         CopyMemory tLI, ByVal lPtr, Len(tLI)
  1226.         ' Lock the memory again:
  1227.         GlobalUnlock hMem
  1228.     End If
  1229. End Sub
  1230. Private Sub pWriteItemInfo( _
  1231.         ByVal hMem As Long, _
  1232.         ByRef tLI As ICONLISTBOXITEMINFO _
  1233.     )
  1234. Dim lPtr As Long
  1235.     ' Get a pointer to the memory block
  1236.     ' pointed to by hMem:
  1237.     lPtr = GlobalLock(hMem)
  1238.     ' Copy the memory into tLI
  1239.     CopyMemory ByVal lPtr, tLI, Len(tLI)
  1240.     ' Lock the memory again:
  1241.     GlobalUnlock hMem
  1242.         
  1243. End Sub
  1244.  
  1245. Property Get ListCount() As Long
  1246. Attribute ListCount.VB_Description = "Gets the number of items in the control's list."
  1247. Dim wMsg As Long
  1248.     If (m_eStyle And ecsListBox) = ecsListBox Then
  1249.         wMsg = LB_GETCOUNT
  1250.     Else
  1251.         wMsg = CB_GETCOUNT
  1252.     End If
  1253.     ListCount = SendMessageByLong(m_hWnd, wMsg, 0, 0)
  1254. End Property
  1255. Property Let itemHeight( _
  1256.         ByVal lIndex As Long, _
  1257.         ByVal lItemHeight As Long _
  1258.     )
  1259. Attribute itemHeight.VB_Description = "Gets/sets the height of an item in the control."
  1260. Dim wMsg As Long
  1261. Dim tLI As ICONLISTBOXITEMINFO
  1262.     m_lR = plGetItemData(lIndex)
  1263.     If (m_lR <> CB_ERR) Then
  1264.         pGetItemInfo m_lR, tLI
  1265.         If (lItemHeight > 0) Then
  1266.             tLI.lItemHeight = lItemHeight
  1267.         Else
  1268.             tLI.lItemHeight = 16
  1269.         End If
  1270.         pWriteItemInfo m_lR, tLI
  1271.         If (m_eStyle And ecsListBox) = ecsListBox Then
  1272.             wMsg = LB_SETITEMHEIGHT
  1273.         Else
  1274.             wMsg = CB_SETITEMHEIGHT
  1275.         End If
  1276.         SendMessageByLong m_hWnd, wMsg, lIndex, tLI.lItemHeight
  1277.     End If
  1278.     
  1279. End Property
  1280. Property Get itemHeight( _
  1281.         ByVal lIndex As Long _
  1282.     ) As Long
  1283. Dim tLI As ICONLISTBOXITEMINFO
  1284.     m_lR = plGetItemData(lIndex)
  1285.     If (m_lR <> CB_ERR) Then
  1286.         ' m_lR is a pointer to a memory block:
  1287.         pGetItemInfo m_lR, tLI
  1288.         itemHeight = tLI.lItemHeight
  1289.     Else
  1290.         itemHeight = 0
  1291.     End If
  1292.  
  1293. End Property
  1294.  
  1295. Property Let itemData( _
  1296.         ByVal lIndex As Long, _
  1297.         ByVal lItemData As Long _
  1298.     )
  1299. Attribute itemData.VB_Description = "Gets/sets a long value associated withf an item in the control."
  1300. Dim wMsg As Long
  1301. Dim tLI As ICONLISTBOXITEMINFO
  1302.     m_lR = plGetItemData(lIndex)
  1303.     If (m_lR <> CB_ERR) Then
  1304.         pGetItemInfo m_lR, tLI
  1305.         tLI.lItemData = lItemData
  1306.         pWriteItemInfo m_lR, tLI
  1307.     End If
  1308. End Property
  1309.  
  1310. Property Get itemData( _
  1311.         ByVal lIndex As Long _
  1312.     ) As Long
  1313. Dim tLI As ICONLISTBOXITEMINFO
  1314.     m_lR = plGetItemData(lIndex)
  1315.     If (m_lR <> CB_ERR) Then
  1316.         ' m_lR is a pointer to a memory block:
  1317.         pGetItemInfo m_lR, tLI
  1318.         itemData = tLI.lItemData
  1319.     Else
  1320.         itemData = 0
  1321.     End If
  1322.  
  1323. End Property
  1324. Private Function plGetItemData( _
  1325.         ByVal lIndex As Long _
  1326.     ) As Long
  1327. Dim wMsg As Long
  1328.     If (m_eStyle And ecsListBox) = ecsListBox Then
  1329.         wMsg = LB_GETITEMDATA
  1330.     Else
  1331.         wMsg = CB_GETITEMDATA
  1332.     End If
  1333.     m_lR = SendMessageByLong(m_hWnd, wMsg, lIndex, 0)
  1334.     If (m_lR = CB_ERR) Then
  1335.         Err.Raise 381, App.EXEName & ".ODCboLst"
  1336.     End If
  1337.     plGetItemData = m_lR
  1338. End Function
  1339. Public Sub Clear()
  1340. Attribute Clear.VB_Description = "Clears all the list items from the list box or combo box."
  1341. Dim lR As Long
  1342. Dim wMsg As Long
  1343. Dim hMem As Long
  1344.     ' For each item in the control, free the memory
  1345.     ' associated with it holding the extended data:
  1346.     For lR = 0 To ListCount - 1
  1347.         hMem = plGetItemData(lR)
  1348.         GlobalFree hMem
  1349.     Next lR
  1350.     ' Now we can clear the control as normal:
  1351.     If (m_eStyle And ecsListBox) = ecsListBox Then
  1352.         wMsg = LB_RESETCONTENT
  1353.     Else
  1354.         wMsg = CB_RESETCONTENT
  1355.     End If
  1356.     lR = SendMessageByLong(m_hWnd, wMsg, 0, 0)
  1357.     
  1358.     ' Set last added item to -1:
  1359.     m_lNewItem = -1
  1360. End Sub
  1361.  
  1362. Public Function FindItemIndex( _
  1363.         ByVal sToFind As String, _
  1364.         Optional ByVal bExactMatch As Boolean = False _
  1365.     ) As Long
  1366. Attribute FindItemIndex.VB_Description = "Finds an item in the list items of a combo or list box."
  1367. Dim lR As Long
  1368. Dim lFlag As Long
  1369.     ' Find the index of the item sToFind, optionally
  1370.     ' exact matching.  Return -1 if the item is not
  1371.     ' found.
  1372.     If (m_hWnd <> 0) Then
  1373.         ' Set the message to send to the control:
  1374.         If (bExactMatch) Then
  1375.             If (m_eStyle And ecsListBox) = ecsListBox Then
  1376.                 lFlag = LB_FINDSTRINGEXACT
  1377.             Else
  1378.                 lFlag = CB_FINDSTRINGEXACT
  1379.             End If
  1380.         Else
  1381.             If (m_eStyle And ecsListBox) = ecsListBox Then
  1382.                 lFlag = LB_FINDSTRING
  1383.             Else
  1384.                 lFlag = CB_FINDSTRING
  1385.             End If
  1386.         End If
  1387.         ' Find:
  1388.         lR = -1
  1389.         lR = SendMessageByString(m_hWnd, lFlag, 0, sToFind)
  1390.         ' Return value:
  1391.         FindItemIndex = lR
  1392.     End If
  1393. End Function
  1394. Public Sub ShowDropDown(ByVal bState As Boolean)
  1395. Attribute ShowDropDown.VB_Description = "Makes a combo box drop down."
  1396. Dim wP As Long
  1397. Dim lR As Long
  1398.     ' In a combo box, show or hide the drop down portion:
  1399.     If (m_eStyle <> ecsListBox) Then
  1400.         If (m_hWnd <> 0) Then
  1401.             wP = -1 * bState
  1402.             lR = SendMessageByLong(m_hWnd, CB_SHOWDROPDOWN, wP, 0)
  1403.         End If
  1404.     End If
  1405. End Sub
  1406. Public Sub ShowDropDownAtPosition( _
  1407.         ByVal xPixels As Long, _
  1408.         ByVal yPixels As Long, _
  1409.         Optional ByVal WidthPixels As Long = 0, _
  1410.         Optional ByVal HeightPixels As Long = 0 _
  1411.     )
  1412. Attribute ShowDropDownAtPosition.VB_Description = "Makes a combo box drop down and moves the drop down list to the specified position."
  1413. Dim tP As POINTAPI, lhWNd As Long
  1414.     ' In a combo box, show or hide the drop down portion at
  1415.     ' a specified location on screen.  Optionally, the width
  1416.     ' and height of the drop down can be specified too.
  1417.     '
  1418.     ' Note that xPixels and yPixels should be specified
  1419.     ' relative to the parent of the UserControl, i.e. if the
  1420.     ' control is a child of a PictureBox, the coordinates
  1421.     ' are relative to the top left of that PictureBox.
  1422.     '
  1423.     If (m_eStyle <> ecsListBox) Then
  1424.         If (m_hWnd <> 0) Then
  1425.             ' Store size to show
  1426.             If (WidthPixels = 0) Then
  1427.                 m_lPW = m_lWidth
  1428.             Else
  1429.                 m_lPW = WidthPixels
  1430.             End If
  1431.             m_lPH = HeightPixels
  1432.             ' Get the parent on which the user control is placed
  1433.             ' so we can evaluate where xPixels and yPixels are in
  1434.             ' terms of screen coordinates (the drop down list portion
  1435.             ' of a combo box is a child of the desktop)
  1436.             lhWNd = GetParent(GetParent(m_hWnd))
  1437.             ' Get position to show in screen coordinates:
  1438.             tP.X = xPixels
  1439.             tP.Y = yPixels
  1440.             ClientToScreen lhWNd, tP
  1441.             m_lPX = tP.X
  1442.             m_lPY = tP.Y
  1443.                     
  1444.             ' Set flag indicating to move drop down on show:
  1445.             m_bPositionDropDown = True
  1446.             
  1447.             ' Tell the combo box to drop down.  The sizing
  1448.             ' and positioning of the list box portion is done
  1449.             ' in response to the WM_CTLCOLORLISTBOX message,
  1450.             ' which is the only message which provides the
  1451.             ' hWnd of the listbox portion of a combo box:
  1452.             SendMessageByLong m_hWnd, CB_SHOWDROPDOWN, 1, 0
  1453.             
  1454.         End If
  1455.     End If
  1456. End Sub
  1457. Property Get Enabled() As Boolean
  1458. Attribute Enabled.VB_Description = "Gets/sets whether the control is enabled."
  1459.     ' Implement Enabled property locally so we
  1460.     ' can set control window enabled
  1461.     Enabled = UserControl.Enabled
  1462. End Property
  1463. Property Let Enabled(bEnabled As Boolean)
  1464. Dim lEnable As Long
  1465. Dim rc As RECT
  1466.     ' Implement Enabled property locally so we
  1467.     ' can set control window enabled
  1468.     If (UserControl.Enabled <> bEnabled) Then
  1469.         ' Set the UserControl state
  1470.         UserControl.Enabled = bEnabled
  1471.         lEnable = bEnabled * -1
  1472.         ' Ensure the control window has the same state also:
  1473.         EnableWindow m_hWnd, lEnable
  1474.         rc.Right = UserControl.ScaleWidth \ Screen.TwipsPerPixelX
  1475.         rc.Bottom = UserControl.ScaleHeight \ Screen.TwipsPerPixelY
  1476.         ' Ensure window is drawn correctly:
  1477.         InvalidateRect m_hWnd, rc, 1
  1478.         ' Notify propchange
  1479.         PropertyChanged "Enabled"
  1480.     End If
  1481. End Property
  1482.  
  1483. Property Get ClientDraw() As EODCLDrawMode
  1484. Attribute ClientDraw.VB_Description = "Gets/sets the way in which the combo box or list box is drawn."
  1485. Attribute ClientDraw.VB_ProcData.VB_Invoke_Property = ";Behavior"
  1486.     ' Return the current Client Draw mode:
  1487.     ClientDraw = m_eClientDraw
  1488. End Property
  1489. Property Let ClientDraw(ByVal eClientDraw As EODCLDrawMode)
  1490.     ' Set the Client Draw mode:
  1491.     If (m_eClientDraw <> eClientDraw) Then
  1492.         m_eClientDraw = eClientDraw
  1493.         If (eClientDraw = ecdParagraphStyles) Or (eClientDraw = ecdFontPicker) Then
  1494.             If Not (m_cIL Is Nothing) Then
  1495.                 m_hIml = m_cIL.hIml
  1496.                 m_hImlCache = m_hIml
  1497.             End If
  1498.         Else
  1499.             m_hIml = m_hImlCache
  1500.         End If
  1501.         pRefreshControl
  1502.         PropertyChanged "ClientDraw"
  1503.     End If
  1504. End Property
  1505.  
  1506. Property Get BackColor() As OLE_COLOR
  1507. Attribute BackColor.VB_Description = "Gets/sets the back color of the control."
  1508. Attribute BackColor.VB_ProcData.VB_Invoke_Property = "StandardColor;Appearance"
  1509.     ' Return the control's default back color:
  1510.     BackColor = UserControl.BackColor
  1511. End Property
  1512. Property Let BackColor(ByVal oBackColor As OLE_COLOR)
  1513.     ' Set the control's default back color:
  1514.     If (UserControl.BackColor <> oBackColor) Then
  1515.         ' Cache the back color value using the UserControl:
  1516.         UserControl.BackColor = oBackColor
  1517.         
  1518.         ' The list box or combo box window has its back colour
  1519.         ' set by the WM_CTLCOLORLISTBOX message.  If the BackColor
  1520.         ' is not the default for the control (Window Background
  1521.         ' colour) we return a brush in response to this message,
  1522.         ' which in turn Windows uses to draw the background:
  1523.         
  1524.         ' Clear background brush if we have one:
  1525.         If (m_hBackBrush <> 0) Then
  1526.             DeleteObject m_hBackBrush
  1527.         End If
  1528.         If (oBackColor <> vbWindowBackground) Then
  1529.             ' Create a background brush:
  1530.             m_hBackBrush = CreateSolidBrush(gTranslateColor(oBackColor))
  1531.         End If
  1532.         
  1533.         PropertyChanged "BackColor"
  1534.     End If
  1535. End Property
  1536. Property Get ForeColor() As OLE_COLOR
  1537. Attribute ForeColor.VB_Description = "Gets/sets the default fore (text) color of the control."
  1538.     ' Return the control's default fore color:
  1539.     ForeColor = UserControl.ForeColor
  1540. End Property
  1541. Property Let ForeColor(ByVal oForeColor As OLE_COLOR)
  1542.     ' Set the control's default fore color:
  1543.     If (UserControl.ForeColor <> oForeColor) Then
  1544.         UserControl.ForeColor = oForeColor
  1545.         PropertyChanged "ForeColor"
  1546.     End If
  1547. End Property
  1548. Property Get Font() As StdFont
  1549. Attribute Font.VB_Description = "Gets/sets the default font for items a list box or combo box."
  1550.     ' Get the control's default font:
  1551.     Set Font = UserControl.Font
  1552. End Property
  1553. Property Set Font(fntThis As StdFont)
  1554. Dim hUFnt As Long
  1555.     ' Set the control's default font:
  1556.     Set UserControl.Font = fntThis
  1557.     ' Store a log font structure for this font:
  1558.     pOLEFontToLogFont fntThis, UserControl.hdc, m_tULF
  1559.     ' Store old font handle:
  1560.     hUFnt = m_hUFnt
  1561.     ' Create a new version of the font:
  1562.     m_hUFnt = CreateFontIndirect(m_tULF)
  1563.     ' Ensure the edit portion has the correct font:
  1564.     If (m_hWnd <> 0) Then
  1565.         SendMessage m_hWnd, WM_SETFONT, m_hUFnt, 1
  1566.     End If
  1567.     ' Delete previous version, if we had one:
  1568.     If (hUFnt <> 0) Then
  1569.         DeleteObject hUFnt
  1570.     End If
  1571.     ' Now it is likely the size of the edit box portion is incorrect.
  1572.     ' **********************************************************
  1573.     ' *** How do we fix it? Any answers to this question will
  1574.     '     be greatly appreciated! ***
  1575.     ' **********************************************************
  1576.     
  1577.     PropertyChanged "Font"
  1578. End Property
  1579. Property Get ExtendedUI() As Boolean
  1580. Attribute ExtendedUI.VB_Description = "Gets/sets whether the list box portion of a combo box will drop down in response to the down key rather than the F4 key."
  1581.     ' Whether a dropdownlist combo box drops down in
  1582.     ' response to the down arrow as well as F4
  1583.     ExtendedUI = m_bExtendedUI
  1584. End Property
  1585. Property Let ExtendedUI(ByVal bExtendedUI As Boolean)
  1586. Dim lS As Long
  1587. Dim lR As Long
  1588.     ' Whether a dropdownlist combo box drops down in
  1589.     ' response to the down arrow as well as F4
  1590.     If m_bExtendedUI <> bExtendedUI Then
  1591.         m_bExtendedUI = bExtendedUI
  1592.         If (m_eStyle <> ecsListBox) Then
  1593.             If (m_hWnd <> 0) Then
  1594.                 lS = -1 * (bExtendedUI = True)
  1595.                 lR = SendMessageByLong(m_hWnd, CB_SETEXTENDEDUI, lS, 0)
  1596.             End If
  1597.         End If
  1598.         PropertyChanged "ExtendedUI"
  1599.     End If
  1600. End Property
  1601. Property Get Style() As EODCLStyle
  1602. Attribute Style.VB_Description = "Gets/sets the type of list box or combo box the control will be."
  1603.     ' Get the Style
  1604.     Style = m_eStyle
  1605. End Property
  1606. Property Let Style(ByVal eStyle As EODCLStyle)
  1607.     ' Set the Style.  Note changing this property during
  1608.     ' run mode will have no effect...  Should raise an
  1609.     ' error, really.  Alternatively this could actually
  1610.     ' change the style of the box.  Since to get a new
  1611.     ' style the original window has to be destroyed, you
  1612.     ' would have to store all the items and their associated
  1613.     ' extended properties, remove the subclass, call pInitialise
  1614.     ' for the new style, make a new subclass and then add the
  1615.     ' items again.
  1616.     If (m_eStyle <> eStyle) Then
  1617.         m_eStyle = eStyle
  1618.         ' If in design mode (no items in the box) then
  1619.         ' change
  1620.         If Not (UserControl.Ambient.UserMode) Then
  1621.             pInitialise
  1622.         End If
  1623.         UserControl.BorderStyle = ((m_eStyle And ecsListBox) = ecsListBox) * -1
  1624.         PropertyChanged "Style"
  1625.     End If
  1626. End Property
  1627. Property Get Sorted() As Boolean
  1628. Attribute Sorted.VB_Description = "Gets/sets whether the list items in the control will be sorted."
  1629.     ' Whether the control is sorted or not:
  1630.     Sorted = m_bSorted
  1631. End Property
  1632. Property Let Sorted(ByVal bSorted As Boolean)
  1633.     ' THis will have no effect at runtime:
  1634.     If (bSorted <> m_bSorted) Then
  1635.         m_bSorted = bSorted
  1636.         PropertyChanged "Sorted"
  1637.     End If
  1638. End Property
  1639. Property Get DropDownWidth() As Long
  1640. Attribute DropDownWidth.VB_Description = "Gets/sets the width to show the drop down portion of a combo box."
  1641.     ' Get the width of the drop down portion of a combo box
  1642.     ' in pixels:
  1643.     DropDownWidth = m_lWidth
  1644. End Property
  1645. Property Let DropDownWidth(lWidth As Long)
  1646. Dim lAWidth As Long
  1647.     ' Set the width of the drop down portion of a combo box
  1648.     ' in pixels:
  1649.     If (m_lWidth <> lWidth) Then
  1650.         m_lWidth = lWidth
  1651.         If (m_eStyle <> ecsListBox) Then
  1652.             If (m_hWnd <> 0) Then
  1653.                 ' The width of a combo box's drop down is set
  1654.                 ' in dialog units which are basically the size
  1655.                 ' of an average character in the system font:
  1656.                 lAWidth = lWidth \ glGetFontDialogUnits(m_hWnd)
  1657.                 m_lR = SendMessageByLong(m_hWnd, CB_SETDROPPEDWIDTH, lAWidth, 0)
  1658.                 If (m_eStyle = ecsDropDownCombo) Then
  1659.                     SelLength = 0
  1660.                 End If
  1661.             End If
  1662.         End If
  1663.         PropertyChanged "DropDownWidth"
  1664.     End If
  1665. End Property
  1666.  
  1667. Private Sub pAmbient()
  1668.     ' set relevant ambient properties:
  1669.     With UserControl.Ambient
  1670.         Set Font = .Font
  1671.         ForeColor = .ForeColor
  1672.     End With
  1673. End Sub
  1674. Private Sub pCreateImageList()
  1675. Dim i As Long
  1676.     ' Create an internal ImageList based on the resources stored in
  1677.     ' picRes.  Probably neater to use an actual resource file
  1678.     ' with the control.
  1679.     Set m_cIL = New CImageList
  1680.     m_cIL.Create picRes.hdc, Size16
  1681.     For i = 0 To 112 Step 16
  1682.         m_cIL.AddFromPictureBox picRes.hdc, picRes, i, 0
  1683.     Next i
  1684.     ' During initialisation, we want to set the ImageList
  1685.     ' to the correct version
  1686.     If (m_eClientDraw = ecdParagraphStyles) Or (m_eClientDraw = ecdFontPicker) Or (m_eStyle = ecsListBoxChecked) Then
  1687.         m_hImlCache = m_hIml
  1688.         m_hIml = m_cIL.hIml
  1689.         m_lIconWidth = m_cIL.IconSize
  1690.     End If
  1691.  
  1692. End Sub
  1693. Private Sub pInitialise()
  1694. Dim hInst As Long
  1695. Dim sStyle As String
  1696. Dim wStyle As Long
  1697. Dim lW As Long, lH As Long
  1698.     
  1699.     ' If we already have a window, then destroy it:
  1700.     pDestroyComboBox
  1701.     
  1702.     ' Create the combo box:
  1703.     hInst = App.hInstance 'GetWindowLong(UserControl.hwnd, GWL_HINSTANCE)
  1704.     
  1705.     ' Set up style bits to get the appropriate type of
  1706.     ' window:
  1707.     If (m_eStyle And ecsListBox) = ecsListBox Then
  1708.         sStyle = "LISTBOX"
  1709.         wStyle = WS_VISIBLE Or WS_CHILD Or WS_VSCROLL Or LBS_HASSTRINGS Or LBS_OWNERDRAWVARIABLE Or LBS_NOTIFY
  1710.         If (m_bSorted) Then
  1711.             wStyle = wStyle Or LBS_SORT
  1712.         End If
  1713.         If (m_eStyle = ecsListBoxMultiSelectExtended) Then
  1714.             wStyle = wStyle Or LBS_EXTENDEDSEL
  1715.         End If
  1716.         If (m_eStyle = ecsListBoxChecked) Or (m_eStyle = ecsListBoxMultiSelectSimple) Then
  1717.             wStyle = wStyle Or LBS_MULTIPLESEL
  1718.         End If
  1719.     Else
  1720.         sStyle = "COMBOBOX"
  1721.         wStyle = WS_VISIBLE Or WS_CHILD Or WS_VSCROLL Or CBS_HASSTRINGS Or CBS_OWNERDRAWVARIABLE
  1722.         If (m_bSorted) Then
  1723.             wStyle = wStyle Or CBS_SORT
  1724.         End If
  1725.         If (m_eStyle = ecsDropDownCombo) Then
  1726.             wStyle = wStyle Or CBS_DROPDOWN Or CBS_AUTOHSCROLL
  1727.         Else
  1728.             wStyle = wStyle Or CBS_DROPDOWNLIST
  1729.         End If
  1730.     End If
  1731.     ' Create the window:
  1732.    m_hWndparent = UserControl.hwnd
  1733.     m_hWnd = CreateWindowEx( _
  1734.         0, _
  1735.         sStyle, _
  1736.         "", _
  1737.         wStyle, _
  1738.         0, 0, lW, lH, _
  1739.         m_hWndparent, _
  1740.         0, _
  1741.         hInst, _
  1742.         ByVal 0 _
  1743.         )
  1744.     ' If we succeed
  1745.     If (m_hWnd <> 0) Then
  1746.         ' Debug.Print m_hWnd
  1747.         'SetParent m_hWnd, UserControl.hwnd
  1748.         ' Ensure showing (probably not necessary thanks to
  1749.         ' WS_VISIBLE style bit):
  1750.         ShowWindow m_hWnd, SW_SHOWNORMAL
  1751.         ' Get the hWnd of the edit box if this is a drop
  1752.         ' down combo:
  1753.         If (m_eStyle = ecsDropDownCombo) Then
  1754.             m_hWndEdit = GetWindow(m_hWnd, GW_CHILD)
  1755.         End If
  1756.         ' Initialise the font for the control:
  1757.         If (m_hUFnt <> 0) Then
  1758.             SendMessage m_hWnd, WM_SETFONT, m_hUFnt, 1
  1759.             If (m_hWndEdit <> 0) Then
  1760.                 SendMessage m_hWndEdit, WM_SETFONT, m_hUFnt, 1
  1761.             End If
  1762.         End If
  1763.     Else
  1764.         ' Debug.Assert (m_hWnd <> 0)
  1765.     End If
  1766.  
  1767.     
  1768. End Sub
  1769. Private Sub pDestroyComboBox()
  1770.     
  1771.     ' If we have a combo box, hide it, set its parent
  1772.     ' to the desktop and then destroy it:
  1773.     If (m_hWnd <> 0) Then
  1774.         ShowWindow m_hWnd, SW_HIDE
  1775.         SetParent m_hWnd, 0
  1776.         DestroyWindow m_hWnd
  1777.     End If
  1778.  
  1779. End Sub
  1780. Private Sub pSubClass()
  1781. Dim lhWNd As Long
  1782. Dim i As Long
  1783.     ' If we have a valid hWnd for the combo box, then add the subclassing
  1784.     ' messages:
  1785.    If (m_hWnd <> 0) Then
  1786.       lhWNd = m_hWndparent
  1787.       AttachMessage Me, lhWNd, WM_COMMAND
  1788.       AttachMessage Me, lhWNd, WM_MEASUREITEM
  1789.       AttachMessage Me, lhWNd, WM_DRAWITEM
  1790.       AttachMessage Me, lhWNd, WM_CTLCOLORLISTBOX
  1791.       AttachMessage Me, lhWNd, WM_SETFOCUS
  1792.       If (m_eStyle = ecsDropDownCombo) Then
  1793.          AttachMessage Me, m_hWndEdit, WM_KEYDOWN
  1794.          AttachMessage Me, m_hWndEdit, WM_CHAR
  1795.       Else
  1796.          AttachMessage Me, m_hWnd, WM_KEYDOWN
  1797.          AttachMessage Me, m_hWnd, WM_CHAR
  1798.       End If
  1799.  
  1800.       m_bSubClass = True
  1801.    End If
  1802. End Sub
  1803. Private Sub pTerminate()
  1804. Dim lhWNd As Long
  1805.     ' Clear up subclassing messages:
  1806.     If (m_bSubClass) Then
  1807.         lhWNd = m_hWndparent
  1808.         DetachMessage Me, lhWNd, WM_COMMAND
  1809.         DetachMessage Me, lhWNd, WM_MEASUREITEM
  1810.         DetachMessage Me, lhWNd, WM_DRAWITEM
  1811.         DetachMessage Me, lhWNd, WM_CTLCOLORLISTBOX
  1812.         DetachMessage Me, lhWNd, WM_SETFOCUS
  1813.          If (m_eStyle = ecsDropDownCombo) Then
  1814.             'DetachMessage Me, m_hWndEdit, WM_KEYDOWN
  1815.             'DetachMessage Me, m_hWndEdit, WM_CHAR
  1816.          Else
  1817.             'DetachMessage Me, m_hWnd, WM_KEYDOWN
  1818.             'DetachMessage Me, m_hWnd, WM_CHAR
  1819.          End If
  1820.     End If
  1821.     
  1822.     ' Clear up image list if any:
  1823.     Set m_cIL = Nothing
  1824.     
  1825.     ' Remove item font if we have one:
  1826.     If (m_hFnt <> 0) Then
  1827.         DeleteObject m_hFnt
  1828.     End If
  1829.  
  1830.     ' Clear the combo box window:
  1831.     pDestroyComboBox
  1832.     ' Remove control font if we have one:
  1833.     If (m_hUFnt <> 0) Then
  1834.         DeleteObject m_hUFnt
  1835.     End If
  1836.  
  1837.     ' Clear background brush if we have one:
  1838.     If (m_hBackBrush <> 0) Then
  1839.         DeleteObject m_hBackBrush
  1840.     End If
  1841.  
  1842. End Sub
  1843. Private Sub pOLEFontToLogFont(fntThis As StdFont, hdc As Long, tLF As LOGFONT)
  1844. Dim sFont As String
  1845. Dim iChar As Integer
  1846.  
  1847.     ' Convert an OLE StdFont to a LOGFONT structure:
  1848.     With tLF
  1849.         sFont = fntThis.Name
  1850.         ' There is a quicker way involving StrConv and CopyMemory, but
  1851.         ' this is simpler!:
  1852.         For iChar = 1 To Len(sFont)
  1853.             .lfFaceName(iChar - 1) = CByte(Asc(Mid$(sFont, iChar, 1)))
  1854.         Next iChar
  1855.         ' Based on the Win32SDK documentation:
  1856.         .lfHeight = -MulDiv((fntThis.Size), (GetDeviceCaps(hdc, LOGPIXELSY)), 72)
  1857.         .lfItalic = fntThis.Italic
  1858.         If (fntThis.Bold) Then
  1859.             .lfWeight = FW_BOLD
  1860.         Else
  1861.             .lfWeight = FW_NORMAL
  1862.         End If
  1863.         .lfUnderline = fntThis.Underline
  1864.         .lfStrikeOut = fntThis.Strikethrough
  1865.     End With
  1866.  
  1867. End Sub
  1868. Private Sub pRefreshControl()
  1869. Dim tR As RECT
  1870.     ' Invalidate the control so it gets redrawn:
  1871.     If (m_hWnd <> 0) Then
  1872.         tR.Right = UserControl.ScaleWidth \ Screen.TwipsPerPixelX
  1873.         tR.Bottom = UserControl.ScaleHeight \ Screen.TwipsPerPixelY
  1874.         InvalidateRect m_hWnd, tR, 1
  1875.     End If
  1876. End Sub
  1877. Private Sub pInitialiseSysColors()
  1878.     
  1879.     ' If SysColorPicker client draw style is chosen, add
  1880.     ' all the colours to it:
  1881.     Clear
  1882.       'assign system color names
  1883.      AddItemAndData "3DDKShadow", , , , vb3DDKShadow
  1884.      AddItemAndData "3DFace", , , , vb3DFace
  1885.      AddItemAndData "3DHighlight", , , , vb3DHighlight
  1886.      AddItemAndData "3DLight", , , , vb3DLight
  1887.      AddItemAndData "3DShadow", , , , vb3DShadow
  1888.      AddItemAndData "ActiveBorder", , , , vbActiveBorder
  1889.      AddItemAndData "ActiveTitleBar", , , , vbActiveTitleBar
  1890.      AddItemAndData "ApplicationWorkspace", , , , vbApplicationWorkspace
  1891.      AddItemAndData "ButtonFace", , , , vbButtonFace
  1892.      AddItemAndData "ButtonShadow", , , , vbButtonShadow
  1893.      AddItemAndData "ButtonText", , , , vbButtonText
  1894.      AddItemAndData "Desktop", , , , vbDesktop
  1895.      AddItemAndData "GrayText", , , , vbGrayText
  1896.      AddItemAndData "Highlight", , , , vbHighlight
  1897.      AddItemAndData "HighlightText", , , , vbHighlightText
  1898.      AddItemAndData "InactiveBorder", , , , vbInactiveBorder
  1899.      AddItemAndData "InactiveCaptionText", , , , vbInactiveCaptionText
  1900.      AddItemAndData "InactiveTitleBar", , , , vbInactiveTitleBar
  1901.      AddItemAndData "InfoBackground", , , , vbInfoBackground
  1902.      AddItemAndData "InfoText", , , , vbInfoText
  1903.      AddItemAndData "MenuBar", , , , vbMenuBar
  1904.      AddItemAndData "MenuText", , , , vbMenuText
  1905.      AddItemAndData "ScrollBars", , , , vbScrollBars
  1906.      AddItemAndData "TitleBarText", , , , vbTitleBarText
  1907.      AddItemAndData "WindowBackground", , , , vbWindowBackground
  1908.      AddItemAndData "WindowFrame", , , , vbWindowFrame
  1909.      AddItemAndData "WindowText", , , , vbWindowText
  1910.      ListIndex = 0
  1911.  
  1912. End Sub
  1913.  
  1914. Public Sub LoadFonts( _
  1915.         Optional ByVal bIncludeScreenFonts As Boolean = True, _
  1916.         Optional ByVal bIncludePrinterFonts As Boolean = True _
  1917.     )
  1918. Attribute LoadFonts.VB_Description = "Fills a combo or list box with system and/or printer fonts."
  1919.     ' Load up the control with fonts.  This will work best
  1920.     ' if
  1921.     Clear
  1922.     If (bIncludeScreenFonts) Then
  1923.         GetFonts UserControl.hdc, Me, False
  1924.     End If
  1925.     If (bIncludePrinterFonts) Then
  1926.         GetFonts Printer.hdc, Me, True
  1927.     End If
  1928. End Sub
  1929.  
  1930. Private Sub pParseTab(ByVal bForward As Boolean)
  1931. Dim i As Long
  1932. Dim iFromTabIndex As Long
  1933. Dim iTabIndex As Long
  1934. Dim iMinTabIndex As Long, iMinTabControl As Long
  1935. Dim iMAxTabIndex As Long, iMaxTabControl As Long
  1936. Dim iPrevTabIndex As Long, iPrevTabControl As Long
  1937. Dim iNextTabIndex As Long, iNextTabControl As Long
  1938. Dim bTabStop As Boolean
  1939. Dim lhWNd As Long
  1940.  
  1941.     iFromTabIndex = UserControl.Extender.TabIndex
  1942.     Debug.Print iFromTabIndex
  1943.     With UserControl.Parent
  1944.  
  1945.         ' Evaluate the next or previous tab stop in the container:
  1946.     
  1947.         iMinTabIndex = .Controls.Count
  1948.         iMAxTabIndex = 0
  1949.         iNextTabControl = -1
  1950.         iPrevTabControl = -1
  1951.         iNextTabIndex = iMinTabIndex
  1952.         iPrevTabIndex = -1
  1953.         iMinTabControl = -1
  1954.         iMaxTabControl = -1
  1955.         
  1956.         For i = 0 To .Controls.Count - 1
  1957.             On Error Resume Next
  1958.             bTabStop = (.Controls(i).TabStop)
  1959.             If (Err.Number = 0) Then
  1960.                 If (bTabStop) Then
  1961.                     iTabIndex = .Controls(i).TabIndex
  1962.                     If (Err.Number = 0) Then
  1963.                         If (iTabIndex <> iFromTabIndex) Then
  1964.                             If (.Controls(i).Enabled) Then
  1965.                                 ' Check global min & max tab indexes:
  1966.                                 If (iTabIndex < iMinTabIndex) Then
  1967.                                     iMinTabIndex = iTabIndex
  1968.                                     iMinTabControl = i
  1969.                                 End If
  1970.                                 If (iTabIndex > iMAxTabIndex) Then
  1971.                                     iMAxTabIndex = iTabIndex
  1972.                                     iMaxTabControl = i
  1973.                                 End If
  1974.                                 ' Determine whether this index is next or prev:
  1975.                                 If (iTabIndex > iFromTabIndex) Then
  1976.                                     If (iNextTabIndex - iFromTabIndex) > (iTabIndex - iFromTabIndex) Then
  1977.                                         iNextTabIndex = iTabIndex
  1978.                                         iNextTabControl = i
  1979.                                     End If
  1980.                                 End If
  1981.                                 If (iTabIndex < iFromTabIndex) Then
  1982.                                     If (iFromTabIndex - iPrevTabIndex) > (iFromTabIndex - iTabIndex) Then
  1983.                                         iPrevTabIndex = iTabIndex
  1984.                                         iPrevTabControl = i
  1985.                                     End If
  1986.                                 End If
  1987.                             Else
  1988.                                 Err.Clear
  1989.                             End If
  1990.                         End If
  1991.                     Else
  1992.                         Err.Clear
  1993.                     End If
  1994.                 Else
  1995.                     Err.Clear
  1996.                 End If
  1997.             Else
  1998.                 Err.Clear
  1999.             End If
  2000.         Next i
  2001.         
  2002.         If (m_eStyle = ecsDropDownCombo) Then
  2003.             lhWNd = m_hWnd
  2004.         Else
  2005.             lhWNd = m_hWndEdit
  2006.         End If
  2007.         
  2008.         If (bForward) Then
  2009.             If (iNextTabControl = -1) Then iNextTabControl = iMinTabControl
  2010.             If (iNextTabControl > -1) Then
  2011.                 'Debug.Print "Forward focus to " & .Controls(iNextTabControl).Name
  2012.                 On Error Resume Next
  2013.                 .Controls(iNextTabControl).SetFocus
  2014.                 Err.Clear
  2015.             End If
  2016.             RaiseEvent ODLostFocus
  2017.         Else
  2018.             If (iPrevTabControl = -1) Then iPrevTabControl = iMaxTabControl
  2019.             If (iPrevTabControl > -1) Then
  2020.                 'Debug.Print "Forward focus to " & .Controls(iPrevTabControl).Name
  2021.                 On Error Resume Next
  2022.                 .Controls(iPrevTabControl).SetFocus
  2023.                 Err.Clear
  2024.             End If
  2025.             RaiseEvent ODLostFocus
  2026.         End If
  2027.     End With
  2028.     
  2029. End Sub
  2030.  
  2031.  
  2032. Private Property Let ISubclass_MsgResponse(ByVal RHS As EMsgResponse)
  2033.     m_emr = RHS
  2034. End Property
  2035.  
  2036. Private Property Get ISubclass_MsgResponse() As EMsgResponse
  2037.    If (CurrentMessage = WM_CHAR) Or (CurrentMessage = WM_KEYDOWN) Or (CurrentMessage = WM_SETFOCUS) Then
  2038.       m_emr = emrConsume
  2039.    Else
  2040.      m_emr = emrPreprocess
  2041.    End If
  2042.    ISubclass_MsgResponse = m_emr
  2043. End Property
  2044.  
  2045. Private Function ISubclass_WindowProc(ByVal hwnd As Long, ByVal iMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  2046. Dim tR As RECT
  2047. Dim lW As Long, lH As Long
  2048. Dim iKeyCode As Integer, iShift As Long, lhWNd As Long, bShift As Boolean
  2049.  
  2050.     'If (hwnd = m_hWndparent) Or (hwnd = m_hWndEdit) Or (hwnd = m_hWnd) Then
  2051.         Select Case iMsg
  2052.         Case WM_CTLCOLORLISTBOX
  2053.             'Debug.Print "CTLCOLORLISTBOX", wParam
  2054.             ' This is the only way to get the handle of the
  2055.             ' list box portion of a combo box:
  2056.             If (m_hWndDropDown = 0) Then
  2057.                 m_hWndDropDown = lParam
  2058.                 ' Now change the width if required:
  2059.                 If (m_lWidth > 0) Or (m_bPositionDropDown) Then
  2060.                   If (IsWindow(m_hWndDropDown)) Then
  2061.                     GetWindowRect m_hWndDropDown, tR
  2062.                     If (m_bPositionDropDown) Then
  2063.                         If (m_lPW <= 0) Then
  2064.                             lW = tR.Right - tR.left
  2065.                         Else
  2066.                             lW = m_lPW
  2067.                         End If
  2068.                         If (m_lPH <= 0) Then
  2069.                             lH = tR.Bottom - tR.tOp
  2070.                         Else
  2071.                             lH = m_lPH
  2072.                         End If
  2073.                         MoveWindow m_hWndDropDown, m_lPX, m_lPY, lW, lH, 1
  2074.                     Else
  2075.                         MoveWindow m_hWndDropDown, tR.left, tR.tOp, m_lWidth, (tR.Bottom - tR.tOp), 1
  2076.                     End If
  2077.                   End If
  2078.                 End If
  2079.             End If
  2080.             If (m_hBackBrush <> 0) Then
  2081.                 ISubclass_WindowProc = m_hBackBrush
  2082.                 m_emr = emrConsume
  2083.             End If
  2084.         Case WM_MEASUREITEM
  2085.             ISubclass_WindowProc = plMeasureItem(wParam, lParam)
  2086.             m_emr = emrConsume
  2087.         Case WM_DRAWITEM
  2088.             ISubclass_WindowProc = plDrawItem(wParam, lParam)
  2089.             m_emr = emrConsume
  2090.         Case WM_COMMAND
  2091.             If (plNotificationEvent(iMsg, wParam, lParam) <> 0) Then
  2092.                 ISubclass_WindowProc = 1
  2093.                 m_emr = emrConsume
  2094.             End If
  2095.         Case WM_KEYDOWN
  2096.             ' Debug.Print "KEYDOWN!", m_hWnd
  2097.             ' Check if we get a tab in the control:
  2098.             iKeyCode = (wParam And &HFF)
  2099.             If (iKeyCode = vbKeyTab) Then
  2100.                 ' shift pressed:
  2101.                 bShift = gbKeyIsPressed(vbKeyShift)
  2102.                 pParseTab Not (bShift)
  2103.                 m_emr = emrConsume
  2104.             Else
  2105.                ' Debug.Print "sending to ", hwnd
  2106.                RaiseEvent KeyDown(iKeyCode, giGetShiftState())
  2107.                 If (iKeyCode = 0) Then
  2108.                     ' consume
  2109.                 Else
  2110.                     wParam = wParam And Not &HFF&
  2111.                     wParam = wParam Or (iKeyCode And &HFF&)
  2112.                     ISubclass_WindowProc = CallOldWindowProc(hwnd, iMsg, wParam, lParam)
  2113.                 End If
  2114.             End If
  2115.          Case WM_CHAR
  2116.             iKeyCode = (wParam And &HFF)
  2117.             If (iKeyCode = vbKeyTab) Then
  2118.                ISubclass_WindowProc = 0
  2119.             Else
  2120.                ' Debug.Print "sending to ", hwnd
  2121.                RaiseEvent KeyPress(iKeyCode)
  2122.                If (iKeyCode = 0) Then
  2123.                   ' consume:
  2124.                Else
  2125.                     If (m_eStyle = ecsDropDownCombo) And (m_bDoAutoComplete) Then
  2126.                         AutoCompleteKeyPress iKeyCode
  2127.                     End If
  2128.                     wParam = wParam And Not &HFF&
  2129.                     wParam = wParam Or (iKeyCode And &HFF&)
  2130.                     ISubclass_WindowProc = CallOldWindowProc(hwnd, iMsg, wParam, lParam)
  2131.                End If
  2132.             End If
  2133.             m_emr = emrConsume
  2134.         Case WM_SETFOCUS
  2135.            ' Debug.Print vbCrLf & "EnterFocus " & UserControl.Extender.Name
  2136.             If (m_eStyle = ecsDropDownCombo) Then
  2137.                lhWNd = m_hWndEdit
  2138.             Else
  2139.                lhWNd = m_hWnd
  2140.             End If
  2141.             If (lhWNd <> 0) Then
  2142.                 ' Debug.Print "Killing user control focus and setting to ", lhWNd
  2143.                 SendMessage UserControl.hwnd, WM_KILLFOCUS, lhWNd, 0
  2144.                 SetFocusAPI lhWNd
  2145.                 ISubclass_WindowProc = 1
  2146.             End If
  2147.         End Select
  2148.     'End If
  2149. End Function
  2150. Private Function plNotificationEvent(ByVal iMsg As Integer, ByVal wParam As Long, ByVal lParam As Long) As Long
  2151. Dim lHiWord As Long, lLoWord As Long
  2152. Dim tR As RECT
  2153.  
  2154.     gGetHiWordLoWord wParam, lHiWord, lLoWord
  2155.     Select Case lHiWord
  2156.     Case CBN_DBLCLK, LBN_DBLCLK
  2157.         RaiseEvent DblClick
  2158.     Case CBN_SETFOCUS, LBN_SETFOCUS
  2159.       ' Debug.Print "GetFocus"
  2160.       RaiseEvent ODGotFocus
  2161.     Case CBN_KILLFOCUS, LBN_KILLFOCUS
  2162.       Debug.Print "KillFocus"
  2163.       If (m_eStyle = ecsListBoxMultiSelectExtended) Or (m_eStyle = ecsListBoxMultiSelectSimple) Then
  2164.         GetClientRect m_hWnd, tR
  2165.         InvalidateRect m_hWnd, tR, 1
  2166.       End If
  2167.       RaiseEvent ODLostFocus
  2168.     Case CBN_SELCHANGE, LBN_SELCHANGE
  2169.       ' Debug.Print "SelChange"
  2170.         RaiseEvent Change
  2171.         RaiseEvent Click
  2172.     Case CBN_SELENDOK
  2173.       ' Debug.Print "SelEndOK"
  2174.         'RaiseEvent Click
  2175.     Case CBN_SELENDCANCEL, LBN_SELCANCEL
  2176.         RaiseEvent SelCancel
  2177.     Case CBN_CLOSEUP
  2178.         If (m_hWndDropDown <> 0) Then
  2179.             m_hWndDropDown = 0
  2180.         End If
  2181.         RaiseEvent CloseUp
  2182.         m_bPositionDropDown = False
  2183.     Case CBN_DROPDOWN
  2184.       ' Debug.Print "DropDown"
  2185.         RaiseEvent DropDown
  2186.     Case CBN_EDITCHANGE
  2187.         RaiseEvent Change
  2188.     End Select
  2189.  
  2190. End Function
  2191. Private Function plKeyEvent(ByVal lhWNd As Long, ByVal iMsg As Integer, ByVal wParam As Long, ByVal lParam As Long) As Long
  2192. Dim iKeyCode As Integer
  2193. Dim iKeyAscii As Integer
  2194. Dim iOrigKeyAscii As Integer
  2195. Dim iShift As Integer
  2196.  
  2197.     iKeyCode = (wParam And &HFF)
  2198.     ' Alt key pressed = Bit 29
  2199.     If ((lParam And &H20000000) = &H20000000) Then
  2200.         iShift = 1
  2201.     End If
  2202.     Select Case iMsg
  2203.     Case WM_KEYDOWN
  2204.         iShift = giGetShiftState()
  2205.         RaiseEvent KeyDown(iKeyCode, iShift)
  2206.         If (m_eStyle = ecsDropDownCombo) Then
  2207.             If IsIn(iMsg, vbKeyReturn, vbKeyUp, vbKeyDown, vbKeyLeft, vbKeyRight) Then
  2208.                 ' debug.print "Consume"
  2209.                 m_emr = emrConsume
  2210.             Else
  2211.                 m_emr = emrPreprocess
  2212.             End If
  2213.         End If
  2214.     Case WM_KEYUP
  2215.         iShift = giGetShiftState()
  2216.         RaiseEvent KeyUp(iKeyCode, iShift)
  2217.     Case WM_CHAR
  2218.         iKeyAscii = (wParam And &HFF)
  2219.         iOrigKeyAscii = iKeyAscii
  2220.         RaiseEvent KeyPress(iKeyAscii)
  2221.         If (iKeyAscii = 0) Then
  2222.             plKeyEvent = 1
  2223.         ElseIf (iKeyAscii <> iOrigKeyAscii) Then
  2224.             SendMessageByLong lhWNd, WM_CHAR, iKeyAscii, 0
  2225.             plKeyEvent = 1
  2226.         End If
  2227.     End Select
  2228.  
  2229. End Function
  2230. Private Function plMeasureItem(ByVal wParam As Long, ByVal lParam As Long) As Long
  2231. Dim tMIs As MEASUREITEMSTRUCT
  2232.     CopyMemory tMIs, ByVal lParam, Len(tMIs)
  2233.     If m_eClientDraw <> ecdClientDrawOnly Then
  2234.         pDefaultMeasureItem tMIs.ItemId, tMIs.itemWidth, tMIs.itemHeight
  2235.     End If
  2236.     If (m_eClientDraw <> ecdNoClientDraw) Then
  2237.         RaiseEvent MeasureItem(tMIs.ItemId, tMIs.itemWidth, tMIs.itemHeight)
  2238.     End If
  2239.     CopyMemory ByVal lParam, tMIs, Len(tMIs)
  2240.     plMeasureItem = 1
  2241. End Function
  2242. Private Function plDrawItem(ByVal wParam As Long, ByVal lParam As Long) As Long
  2243. Dim tDis As DRAWITEMSTRUCT
  2244. Dim bEnabled As Boolean
  2245. Dim bSelected As Boolean
  2246. Dim tLI As ICONLISTBOXITEMINFO
  2247. Dim tLF As LOGFONT
  2248. Dim hMem As Long
  2249.  
  2250.     CopyMemory tDis, ByVal lParam, Len(tDis)
  2251.     
  2252.     ' Evaluate enabled/selected state of item:
  2253.     bEnabled = Not ((tDis.ItemState And ODS_DISABLED) = ODS_DISABLED)
  2254.     bSelected = ((tDis.ItemState And ODS_SELECTED) = ODS_SELECTED)
  2255.     If (bSelected) Then
  2256.         ' Only draw selected in the combo when the
  2257.         ' focus is on the control:
  2258.         If (tDis.ItemState And ODS_COMBOBOXEDIT) = ODS_COMBOBOXEDIT Then
  2259.             If (tDis.ItemState And ODS_FOCUS) <> ODS_FOCUS Then
  2260.                 bSelected = False
  2261.             End If
  2262.         End If
  2263.     End If
  2264.  
  2265.     ' Ensure we have the correct font and colours selected:
  2266.     If (m_bFontNotCreated) Then
  2267.         pOLEFontToLogFont UserControl.Font, UserControl.hdc, m_tlF
  2268.         m_hFnt = CreateFontIndirect(m_tlF)
  2269.         m_bFontNotCreated = False
  2270.     End If
  2271.     ' Get the item data for this item:
  2272.     
  2273.     If (tDis.ItemState And ODS_COMBOBOXEDIT) = ODS_COMBOBOXEDIT Then
  2274.         If Not (pbIsCurrentFont(m_tULF)) Then
  2275.             DeleteObject m_hFnt
  2276.             LSet m_tlF = m_tULF
  2277.             m_hFnt = CreateFontIndirect(m_tlF)
  2278.         End If
  2279.     End If
  2280.     If (tDis.ItemId <> -1) Then
  2281.         hMem = plGetItemData(tDis.ItemId)
  2282.         pGetItemInfo hMem, tLI
  2283.         If (tDis.ItemState And ODS_COMBOBOXEDIT) <> ODS_COMBOBOXEDIT Then
  2284.             If Not (pbIsCurrentFont(tLI.tLF)) Then
  2285.                 DeleteObject m_hFnt
  2286.                 LSet m_tlF = tLI.tLF
  2287.                 m_hFnt = CreateFontIndirect(m_tlF)
  2288.             End If
  2289.         End If
  2290.     Else
  2291.         If Not (pbIsCurrentFont(m_tULF)) Then
  2292.             DeleteObject m_hFnt
  2293.             LSet m_tlF = m_tULF
  2294.             m_hFnt = CreateFontIndirect(m_tlF)
  2295.         End If
  2296.     End If
  2297.     m_hFntOld = SelectObject(tDis.hdc, m_hFnt)
  2298.  
  2299.     If m_eClientDraw <> ecdClientDrawOnly Then
  2300.         ' Draw by default mechanism:
  2301.         pDefaultDrawItem tDis.hdc, tDis.ItemId, tLI, tDis.ItemAction, tDis.ItemState, _
  2302.             tDis.rcItem.left, tDis.rcItem.tOp, tDis.rcItem.Right, tDis.rcItem.Bottom
  2303.     End If
  2304.     If m_eClientDraw <> ecdNoClientDraw Then
  2305.         ' Notify the client its time to draw:
  2306.         RaiseEvent DrawItem(tDis.ItemId, tDis.hdc, _
  2307.                             bSelected, bEnabled, _
  2308.                             tDis.rcItem.left, tDis.rcItem.tOp, tDis.rcItem.Right, tDis.rcItem.Bottom, _
  2309.                             m_hFntOld)
  2310.     End If
  2311.     
  2312.     SelectObject tDis.hdc, m_hFntOld
  2313.     
  2314.     plDrawItem = 1
  2315.     
  2316. End Function
  2317. Private Sub pRedrawItem(ByVal lIndex As Long)
  2318. Dim rc As RECT
  2319.    If (m_eStyle <> ecsDropDownCombo) Then
  2320.       ' Get the rectangle for this item:
  2321.       SendMessage m_hWnd, LB_GETITEMRECT, lIndex, rc
  2322.       ' If visible, then force redraw:
  2323.       InvalidateRect m_hWnd, rc, 1
  2324.    End If
  2325. End Sub
  2326. Private Function pbIsCurrentFont(tLF As LOGFONT) As Boolean
  2327. Dim sCurrentFace As String
  2328. Dim sItemFace As String
  2329.     If (tLF.lfFaceName(0) = 0) Then
  2330.         ' Default
  2331.         pbIsCurrentFont = True
  2332.     Else
  2333.         If (tLF.lfWeight = m_tlF.lfWeight) And (tLF.lfItalic = m_tlF.lfItalic) And (tLF.lfHeight = m_tlF.lfHeight) Then
  2334.             sCurrentFace = StrConv(tLF.lfFaceName, vbUnicode)
  2335.             sItemFace = StrConv(m_tlF.lfFaceName, vbUnicode)
  2336.             If (sCurrentFace = sItemFace) Then
  2337.                 pbIsCurrentFont = True
  2338.             End If
  2339.         End If
  2340.     End If
  2341. End Function
  2342. Private Sub pDefaultMeasureItem( _
  2343.         ByVal litemId As Long, _
  2344.         ByRef lW As Long, ByRef lH As Long _
  2345.     )
  2346. Dim tLI As ICONLISTBOXITEMINFO
  2347. Dim hMem As Long
  2348.     lH = 32
  2349.     If (litemId <> -1) Then
  2350.         hMem = plGetItemData(litemId)
  2351.         pGetItemInfo hMem, tLI
  2352.         If (tLI.lItemHeight > 0) Then
  2353.             lH = tLI.lItemHeight
  2354.         Else
  2355.             lH = 32
  2356.         End If
  2357.     End If
  2358.     If (m_lWidth <= 0) Then
  2359.         lW = UserControl.ScaleWidth \ Screen.TwipsPerPixelX
  2360.     Else
  2361.         lW = m_lWidth
  2362.     End If
  2363. End Sub
  2364. Private Sub pDrawColorPicker( _
  2365.         ByVal hdc As Long, _
  2366.         ByVal Index As Long, _
  2367.         tLI As ICONLISTBOXITEMINFO, _
  2368.         ByVal ItemAction As Long, _
  2369.         ByVal ItemState As Long, _
  2370.         ByVal LeftPixels As Long, ByVal TopPixels As Long, ByVal RightPixels As Long, ByVal BottomPixels As Long _
  2371.     )
  2372. Dim tR As RECT, hBrush As Long, tS As RECT
  2373. Dim hPen As Long, hPenOld As Long
  2374. Dim bSelected As Boolean
  2375.     
  2376.     If (Index <> -1) Then
  2377.     
  2378.         bSelected = ((ItemState And ODS_SELECTED) = ODS_SELECTED)
  2379.  
  2380.         SetBkMode hdc, TRANSPARENT
  2381.         
  2382.         tR.tOp = TopPixels
  2383.         tR.Bottom = BottomPixels
  2384.         tR.left = LeftPixels
  2385.         tR.Right = RightPixels
  2386.         If (bSelected) Then
  2387.             hBrush = CreateSolidBrush(gTranslateColor(vbHighlight))
  2388.             FillRect hdc, tR, hBrush
  2389.             DeleteObject hBrush
  2390.         Else
  2391.             If (ItemAction = ODA_SELECT) Then
  2392.                 hBrush = CreateSolidBrush(gTranslateColor(vbWindowBackground))
  2393.                 FillRect hdc, tR, hBrush
  2394.                 DeleteObject hBrush
  2395.             End If
  2396.         End If
  2397.     
  2398.         'Debug.Print Index, hDC, bSelected, bEnabled, LeftPixels, TopPixels, RightPixels, BottomPixels
  2399.     
  2400.         tR.tOp = TopPixels + 1
  2401.         tR.Bottom = BottomPixels - 1
  2402.         tR.left = LeftPixels + 2
  2403.         If (m_eClientDraw = ecdColourPickerNoNames) Then
  2404.             tR.tOp = tR.tOp + 1
  2405.             tR.Bottom = tR.Bottom - 1
  2406.             tR.Right = RightPixels - 2
  2407.         Else
  2408.             tR.Right = tR.left + (tR.Bottom - tR.tOp)
  2409.         End If
  2410.         ' Draw sunken border:
  2411.         DrawEdge hdc, tR, BDR_SUNKENOUTER Or BDR_SUNKENINNER, (BF_RECT Or BF_MIDDLE)
  2412.         
  2413.         ' Draw the sample colour:
  2414.         hBrush = CreateSolidBrush(gTranslateColor(ItemBackColor(Index)))
  2415.         LSet tS = tR
  2416.         tS.left = tS.left + 2
  2417.         tS.Right = tS.Right - 2
  2418.         tS.tOp = tS.tOp + 2
  2419.         tS.Bottom = tS.Bottom - 2
  2420.         FillRect hdc, tS, hBrush
  2421.         DeleteObject hBrush
  2422.         
  2423.         If (m_eClientDraw <> ecdColourPickerNoNames) Then
  2424.             ' Now write the caption
  2425.             If (bSelected) Then
  2426.                 SetTextColor hdc, gTranslateColor(vbHighlightText)
  2427.             Else
  2428.                 SetTextColor hdc, gTranslateColor(vbWindowText)
  2429.             End If
  2430.             hPenOld = SelectObject(hdc, hPen)
  2431.             tR.left = tR.Right + 2
  2432.             tR.Right = RightPixels
  2433.             DrawTextExAsNull hdc, List(Index), Len(List(Index)), tR, DT_LEFT Or DT_NOPREFIX, 0
  2434.             SelectObject hdc, hPenOld
  2435.             DeleteObject hPen
  2436.         End If
  2437.     End If
  2438.     
  2439. End Sub
  2440. Private Sub pDefaultDrawItem( _
  2441.         ByVal hdc As Long, _
  2442.         ByVal ItemId As Long, _
  2443.         tLI As ICONLISTBOXITEMINFO, _
  2444.         ByVal ItemAction As Long, _
  2445.         ByVal ItemState As Long, _
  2446.         ByVal left As Long, ByVal tOp As Long, ByVal Right As Long, ByVal Bottom As Long _
  2447.     )
  2448. Dim tR As RECT
  2449. Dim tIR As RECT
  2450. Dim hPen As Long
  2451. Dim hPenOld As Long
  2452. Dim hBrush As Long
  2453. Dim sItem As String
  2454. Dim lCOl As Long
  2455. Dim tP As POINTAPI
  2456. Dim hMem As Long
  2457. Dim bSelected As Boolean
  2458. Dim iColCount As Integer
  2459. Dim lLeft As Long
  2460. Dim bFocus As Boolean
  2461. Dim lFocus As Long
  2462.  
  2463.     Debug.Print "DrawItem"
  2464.    lFocus = GetFocus()
  2465.    bFocus = ((lFocus = m_hWnd) Or (lFocus = UserControl.hwnd))
  2466.  
  2467.     ' Determine the default draw mechanism:
  2468.     Select Case m_eClientDraw
  2469.     Case ecdColourPickerWithNames, ecdSysColourPicker, ecdColourPickerNoNames
  2470.         ' Do ColourPicker:
  2471.         pDrawColorPicker hdc, ItemId, tLI, ItemAction, ItemState, left, tOp, Right, Bottom
  2472.     Case Else
  2473.         
  2474.         With tR
  2475.             .left = left
  2476.             .tOp = tOp
  2477.             .Right = Right
  2478.             .Bottom = Bottom
  2479.         End With
  2480.         ' Debug.Print ItemId
  2481.         If (ItemId <> -1) Then
  2482.             sItem = List(ItemId)
  2483.         Else
  2484.             sItem = ""
  2485.             tLI.lBackColour = UserControl.BackColor
  2486.             tLI.lForeColour = UserControl.ForeColor
  2487.             tLI.lIconIndex = -1
  2488.         End If
  2489.         '' Debug.Print sItem, hdc, left, Right, tOp, Bottom
  2490.     
  2491.         If (ItemState And ODS_DISABLED) = ODS_DISABLED Then
  2492.             'hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE))
  2493.             'FillRect hdc, tR, hBrush
  2494.             'DeleteObject hBrush
  2495.             
  2496.             If (m_eClientDraw = ecdParagraphStyles) Or (m_eClientDraw = ecdFontPicker) Then
  2497.                 If (m_eClientDraw = ecdParagraphStyles) Then
  2498.                     tR.Right = tR.Right - 28
  2499.                 End If
  2500.             Else
  2501.                 tR.left = tR.left + m_lBorderLeft
  2502.                 tR.Right = tR.Right - m_lBorderRight
  2503.             End If
  2504.             lLeft = tR.left
  2505.             If (ItemState And ODS_COMBOBOXEDIT) <> ODS_COMBOBOXEDIT Then
  2506.                 tR.left = tR.left + tLI.lIndentSize
  2507.             End If
  2508.             
  2509.             If (tLI.lIconIndex > -1) Then
  2510.                 If (m_eClientDraw = ecdFontPicker) Or (m_eStyle = ecsListBoxChecked) Then
  2511.                     If (m_eStyle = ecsListBoxChecked) Then
  2512.                         If ((ItemState And ODS_SELECTED) = ODS_SELECTED) Then
  2513.                            tLI.lIconIndex = 5
  2514.                         Else
  2515.                            tLI.lIconIndex = 6
  2516.                         End If
  2517.                     End If
  2518.                     ' Use internal image list:
  2519.                     InternalImageList.DrawImage tLI.lIconIndex, hdc, tR.left + 2, tR.tOp, , True
  2520.                 Else
  2521.                     ImageList_DrawEx m_hIml, tLI.lIconIndex, hdc, tR.left + 2, tR.tOp, 0, 0, CLR_NONE, GetSysColor(COLOR_WINDOW), ILD_TRANSPARENT Or ILD_SELECTED
  2522.                 End If
  2523.                 tR.left = tR.left + m_lIconWidth + 4
  2524.             End If
  2525.             If (ItemState And ODS_SELECTED) = ODS_SELECTED Then
  2526.                 lCOl = GetSysColor(COLOR_BTNFACE)
  2527.                 SetBkColor hdc, lCOl
  2528.                 lCOl = GetSysColor(COLOR_WINDOW)
  2529.                 SetBkMode hdc, OPAQUE
  2530.             Else
  2531.                 lCOl = GetSysColor(COLOR_BTNSHADOW)
  2532.                 SetBkMode hdc, TRANSPARENT
  2533.             End If
  2534.             tR.tOp = tR.tOp + 2
  2535.             SetTextColor hdc, lCOl
  2536.             
  2537.             pDrawText hdc, ItemState, sItem, lLeft, (tLI.lTextAlignX Or tLI.lTextAlignY), tR
  2538.             
  2539.         Else
  2540.             SetBkMode hdc, OPAQUE
  2541.             ' Set the forecolour to use for this draw:
  2542.             If (tLI.lForeColour = -1) Then
  2543.                 tLI.lForeColour = UserControl.ForeColor
  2544.             End If
  2545.             
  2546.             ' Determine selection state:
  2547.             bSelected = ((ItemState And ODS_SELECTED) = ODS_SELECTED)
  2548.             If (bSelected) Then
  2549.                 ' For checked list box style we draw an icon depending
  2550.                 ' on the check state:
  2551.                 If (m_eStyle = ecsListBoxChecked) Then
  2552.                     tLI.lIconIndex = 5
  2553.                 End If
  2554.                 ' Only draw selected in the combo when the
  2555.                 ' focus is on the control:
  2556.                 If (ItemState And ODS_COMBOBOXEDIT) = ODS_COMBOBOXEDIT Then
  2557.                     If (ItemState And ODS_FOCUS) <> ODS_FOCUS Then
  2558.                         bSelected = False
  2559.                     End If
  2560.                 End If
  2561.             Else
  2562.                 ' For checked list box style we draw an icon depending
  2563.                 ' on the check state:
  2564.                 If (m_eStyle = ecsListBoxChecked) Then
  2565.                     tLI.lIconIndex = 6
  2566.                 End If
  2567.             End If
  2568.             
  2569.             ' Set the Text Colour of the DC to according to
  2570.             ' the selection state:
  2571.             If bSelected And m_eStyle <> ecsListBoxChecked Then
  2572.                ' Draw selected:
  2573.                If m_eStyle = ecsDropDownCombo Or bFocus Then
  2574.                   lCOl = GetSysColor(COLOR_HIGHLIGHTTEXT)
  2575.                   SetTextColor hdc, lCOl
  2576.                Else
  2577.                   lCOl = GetSysColor(COLOR_WINDOWTEXT)
  2578.                   SetTextColor hdc, lCOl
  2579.                End If
  2580.             Else
  2581.                 ' Draw normal:
  2582.                 lCOl = gTranslateColor(tLI.lForeColour)
  2583.                 SetTextColor hdc, lCOl
  2584.             End If
  2585.                         
  2586.             ' Determine the back colour for this item:
  2587.             If (tLI.lBackColour = -1) Then
  2588.                 lCOl = gTranslateColor(UserControl.BackColor)
  2589.             Else
  2590.                 lCOl = gTranslateColor(tLI.lBackColour)
  2591.             End If
  2592.             
  2593.             ' We only need to clear the background when
  2594.             ' the entire list box is being redrawn, or when
  2595.             ' the full-row select mode is on and the row is
  2596.             ' selected (this avoids some flicker):
  2597.             If (ItemAction = ODA_SELECT) Or (m_bFullRowSelect) Then
  2598.                 If (m_bFullRowSelect) Then
  2599.                     If (bSelected) Then
  2600.                         If m_eStyle = ecsDropDownCombo Or bFocus Then
  2601.                             hBrush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT))
  2602.                         Else
  2603.                             hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE))
  2604.                         End If
  2605.                     Else
  2606.                         hBrush = CreateSolidBrush(lCOl)
  2607.                     End If
  2608.                 Else
  2609.                     hBrush = CreateSolidBrush(lCOl)
  2610.                 End If
  2611.                 FillRect hdc, tR, hBrush
  2612.                 DeleteObject hBrush
  2613.                 'If (m_eStyle > ecsListBox) Then
  2614.                 '    If ListIndex = ItemId Then
  2615.                 '        DrawFocusRect hdc, tR
  2616.                 '    End If
  2617.                 'End If
  2618.             End If
  2619.             SetBkColor hdc, lCOl
  2620.             
  2621.             ' Adjust the drawing boundary rectangle according
  2622.             ' to the drawing style:
  2623.             If (m_eClientDraw = ecdParagraphStyles) Or (m_eClientDraw = ecdFontPicker) Then
  2624.                 If (m_eClientDraw = ecdParagraphStyles) Then
  2625.                     tR.Right = tR.Right - 28
  2626.                 End If
  2627.             Else
  2628.                 tR.left = tR.left + m_lBorderLeft
  2629.                 tR.Right = tR.Right - m_lBorderRight
  2630.             End If
  2631.             
  2632.             lLeft = tR.left
  2633.                         
  2634.             ' Show the indent if this is not the edit box
  2635.             ' portion of the combo box:
  2636.             If (ItemState And ODS_COMBOBOXEDIT) <> ODS_COMBOBOXEDIT Then
  2637.                 tR.left = tR.left + tLI.lIndentSize
  2638.             End If
  2639.             
  2640.             ' If we have an icon, then draw it:
  2641.             If (tLI.lIconIndex > -1) Then
  2642.                 If (m_eClientDraw = ecdFontPicker) Or (m_eStyle = ecsListBoxChecked) Then
  2643.                     ' Use internal image list:
  2644.                     If (m_eStyle = ecsListBoxChecked) Then
  2645.                         ' Ensure we have overdrawn the previous icon:
  2646.                         hBrush = CreateSolidBrush(lCOl)
  2647.                         SetBkColor hdc, lCOl
  2648.                         tIR.left = tR.left + 2
  2649.                         tIR.tOp = tR.tOp
  2650.                         tIR.Right = tR.left + m_lIconWidth
  2651.                         tIR.Bottom = tR.tOp + m_lIconWidth
  2652.                         FillRect hdc, tIR, hBrush
  2653.                         DeleteObject hBrush
  2654.                     End If
  2655.                     InternalImageList.DrawImage tLI.lIconIndex, hdc, tR.left + 2, tR.tOp
  2656.                 Else
  2657.                     ' Use the image list handle specified via the
  2658.                     ' ImageList property:
  2659.                     ImageList_Draw m_hIml, tLI.lIconIndex, hdc, tR.left + 2, tR.tOp, ILD_TRANSPARENT
  2660.                 End If
  2661.                 ' Adjust draw position for the icon:
  2662.                 tR.left = tR.left + m_lIconWidth + 4
  2663.             End If
  2664.             
  2665.             ' Ensure the back colour is correct:
  2666.             If (bSelected) And (m_eStyle <> ecsListBoxChecked) Then
  2667.                If m_eStyle = ecsDropDownCombo Or bFocus Then
  2668.                    lCOl = GetSysColor(COLOR_HIGHLIGHT)
  2669.                 Else
  2670.                    lCOl = GetSysColor(COLOR_BTNFACE)
  2671.                 End If
  2672.                 SetBkColor hdc, lCOl
  2673.             End If
  2674.             ' Adjust top by two pixels if no vertical alignment given
  2675.             If (tLI.lTextAlignY = DT_TOP) Then
  2676.                 tR.tOp = tR.tOp + 2
  2677.             End If
  2678.             
  2679.             ' Draw the text of the item:
  2680.             pDrawText hdc, ItemState, sItem, lLeft, (tLI.lTextAlignX Or tLI.lTextAlignY), tR
  2681.             
  2682.             ' If underlining or overlining is set, then draw
  2683.             ' the item:
  2684.             If (tLI.bUnderLineItem) Or (m_eClientDraw = ecdParagraphStyles) Then
  2685.                 If (ItemState And ODS_COMBOBOXEDIT) <> ODS_COMBOBOXEDIT Then
  2686.                     hPen = CreatePen(PS_SOLID, 1, &H0&)
  2687.                     hPenOld = SelectObject(hdc, hPen)
  2688.                     MoveToEx hdc, left, Bottom - 1, tP
  2689.                     LineTo hdc, Right, Bottom - 1
  2690.                     SelectObject hdc, hPenOld
  2691.                     DeleteObject hPen
  2692.                 End If
  2693.             End If
  2694.             If (tLI.bOverLineItem) Then
  2695.                 If (ItemState And ODS_COMBOBOXEDIT) <> ODS_COMBOBOXEDIT Then
  2696.                     hPen = CreatePen(PS_SOLID, 1, &H0&)
  2697.                     hPenOld = SelectObject(hdc, hPen)
  2698.                     MoveToEx hdc, left, tOp, tP
  2699.                     LineTo hdc, Right, tOp
  2700.                     SelectObject hdc, hPenOld
  2701.                     DeleteObject hPen
  2702.                 End If
  2703.             End If
  2704.             
  2705.             ' If the style is set to paragraph styles, then show
  2706.             ' pt size and paragraph alignment to right of
  2707.             ' combo box:
  2708.             If (m_eClientDraw = ecdParagraphStyles) Then
  2709.                 If (ItemId >= 0) Then
  2710.                     Dim lIcon As Long, tTULF As LOGFONT, hFnt As Long, hFntOld As Long
  2711.                     ' Draw a grey box:
  2712.                     tR.left = Right - 28
  2713.                     tR.Right = Right
  2714.                     tR.tOp = tOp
  2715.                     tR.Bottom = Bottom - 1
  2716.                     hBrush = CreateSolidBrush(&HC0C0C0)
  2717.                     FillRect hdc, tR, hBrush
  2718.                     DeleteObject hBrush
  2719.                     ' Draw info
  2720.                     Select Case tLI.lTextAlignX
  2721.                     Case eixLeft
  2722.                         lIcon = 3
  2723.                     Case eixCentre
  2724.                         lIcon = 2
  2725.                     Case eixRight
  2726.                         lIcon = 4
  2727.                     End Select
  2728.                     InternalImageList.DrawImage lIcon, hdc, tR.left, tR.tOp
  2729.                     
  2730.                     ' Restore old font:
  2731.                     SelectObject hdc, m_hFntOld
  2732.                     ' Create a tiny 7 point font for rendering point
  2733.                     ' size:
  2734.                     LSet tTULF = m_tULF
  2735.                     tTULF.lfHeight = -MulDiv(7, (GetDeviceCaps(hdc, LOGPIXELSY)), 72)
  2736.                     hFnt = CreateFontIndirect(tTULF)
  2737.                     hFntOld = SelectObject(hdc, hFnt)
  2738.                     
  2739.                     tR.tOp = tR.tOp + 18
  2740.                     SetBkColor hdc, &HC0C0C0
  2741.                     sItem = itemData(ItemId) & " pt"
  2742.                     SetTextColor hdc, GetSysColor(COLOR_WINDOWTEXT)
  2743.                     DrawTextExAsNull hdc, sItem, Len(sItem), tR, DT_CENTER Or DT_NOPREFIX, 0
  2744.                                   
  2745.                     ' Reset font to m_hFnt
  2746.                     SelectObject hdc, hFntOld
  2747.                     DeleteObject hFnt
  2748.                     
  2749.                     m_hFntOld = SelectObject(hdc, m_hFnt)
  2750.                 End If
  2751.             End If
  2752.         End If
  2753.     End Select
  2754. End Sub
  2755. Private Sub pDrawText(ByVal hdc As Long, ByVal ItemState As Long, ByVal sItem As String, ByVal lLeft As Long, ByVal lAlign As Long, ByRef tR As RECT)
  2756. Dim tCR As RECT
  2757. Dim iColCount As Integer
  2758. Dim iCol As Integer
  2759. Dim sColVals() As String
  2760.     
  2761.     ' We potentially have > 1 column.  If this isn't the edit portion of a combo
  2762.     ' box, and we have specified that there are > 1 columns for the box,
  2763.     ' then draw according to the specified column widths.  Otherwise, use default
  2764.     ' drawing means.
  2765.     If (m_iColCount > 1) And (ItemState And ODS_COMBOBOXEDIT) <> ODS_COMBOBOXEDIT Then
  2766.         ' Split sItem according to vbTab:
  2767.         gSplitDelimitedString sItem, vbTab, sColVals(), iColCount
  2768.         ' Add attributes to truncate text and draw ellipsis (..) if too long
  2769.         lAlign = lAlign Or DT_END_ELLIPSIS Or DT_MODIFYSTRING Or DT_NOPREFIX
  2770.         ' Set up rectangle for first column
  2771.         LSet tCR = tR
  2772.         tCR.Right = lLeft + m_lColWidth(1)
  2773.         ' Always Draw the first item:
  2774.         If (m_eCoLType(1) = ectImageListIcon) Then
  2775.             ImageList_Draw m_hIml, glCStr(sColVals(1), -1), hdc, tCR.left, tCR.tOp - 2, ILD_TRANSPARENT
  2776.         Else
  2777.             DrawTextExAsNull hdc, sColVals(1), Len(sColVals(1)), tCR, lAlign, 0
  2778.         End If
  2779.         For iCol = 2 To iColCount
  2780.             If (iCol > m_iColCount) Then
  2781.                 ' Don't attempt to draw columns that we don't have:
  2782.                 Exit For
  2783.             End If
  2784.             tCR.left = tCR.Right + 1
  2785.             tCR.Right = tCR.left + m_lColWidth(iCol)
  2786.             Select Case m_eCoLType(iCol)
  2787.             Case ectImageListIcon
  2788.                 ImageList_Draw m_hIml, glCStr(sColVals(iCol), -1), hdc, tCR.left, tCR.tOp - 2, ILD_TRANSPARENT
  2789.             Case Else
  2790.                 DrawTextExAsNull hdc, sColVals(iCol), Len(sColVals(iCol)), tCR, lAlign, 0
  2791.             End Select
  2792.         Next iCol
  2793.     Else
  2794.         lAlign = DT_LEFT Or DT_NOPREFIX
  2795.         DrawTextExAsNull hdc, sItem, Len(sItem), tR, lAlign, 0
  2796.     End If
  2797.         
  2798. End Sub
  2799.  
  2800.  
  2801. Private Sub UserControl_EnterFocus()
  2802.     ' Debug.Print "EnterFocus:" & UserControl.Extender.Name
  2803.     ' Done with Subclass
  2804. End Sub
  2805.  
  2806. Private Sub UserControl_Initialize()
  2807.     Debug.Print "OwnerDraw:Initialise"
  2808.     m_lMaxLength = 30000&
  2809.     m_lNewItem = -1
  2810.     'm_eBorderStyle = ecbBorderStyle3d
  2811. End Sub
  2812.  
  2813. Private Sub UserControl_InitProperties()
  2814.     pAmbient
  2815.     
  2816.     ' Set defaults:
  2817.     m_bSorted = False
  2818.     m_bExtendedUI = False
  2819.     m_lWidth = 0
  2820.     BackColor = &H80000005
  2821.     Style = ecsDropDownList
  2822.     
  2823.     ' Create the owner drawn control:
  2824.     pInitialise
  2825.     
  2826.     ' InitProperties does not occur in runtime environment, therefore
  2827.     ' no need to set up subclass etc.
  2828.     
  2829. End Sub
  2830.  
  2831. Private Sub UserControl_KeyDown(KeyCode As Integer, Shift As Integer)
  2832. Dim lR As Long
  2833. Dim lhWNd As Long
  2834.  
  2835.    If (KeyCode = vbKeyUp) Or (KeyCode = vbKeyDown) Then
  2836.       ' Debug.Print "!!!!KEYUP OR KEYDOWN!!!!"
  2837.    End If
  2838.    
  2839.     ' Send keys on to combo box:
  2840.     'if (m_hWnd <> 0) Then
  2841.       ' Debug.Print "DOing UserControl_KeyDown"
  2842.         If (m_eStyle = ecsDropDownCombo) Then
  2843.            lhWNd = m_hWndEdit
  2844.         Else
  2845.            lhWNd = m_hWnd
  2846.         End If
  2847.         lR = SendMessageByLong(lhWNd, WM_KEYDOWN, KeyCode, 0)
  2848.     'End If
  2849. End Sub
  2850.  
  2851. Private Sub UserControl_KeyPress(KeyAscii As Integer)
  2852. Dim lhWNd As Long
  2853.     If (m_hWnd <> 0) Then
  2854.       If (m_eStyle = ecsDropDownCombo) Then
  2855.          lhWNd = m_hWndEdit
  2856.       Else
  2857.          lhWNd = m_hWnd
  2858.       End If
  2859.         SendMessageByLong m_hWndEdit, WM_CHAR, KeyAscii, 0
  2860.     End If
  2861. End Sub
  2862.  
  2863. Private Sub UserControl_KeyUp(KeyCode As Integer, Shift As Integer)
  2864.     If (m_hWnd <> 0) Then
  2865.         If (KeyCode <> vbKeyTab) Then
  2866.             If (m_eStyle = ecsDropDownCombo) Then
  2867.                 If (KeyCode >= vbKeySpace) Then
  2868.                     SendMessageByLong m_hWndEdit, WM_KEYUP, KeyCode, 0
  2869.                 Else
  2870.                     SendMessageByLong m_hWndEdit, WM_KEYUP, KeyCode, 0
  2871.                 End If
  2872.             Else
  2873.                 SendMessageByLong m_hWnd, WM_KEYUP, KeyCode, 0
  2874.             End If
  2875.          Else
  2876.             ' Debug.Print "Tab"
  2877.         End If
  2878.     End If
  2879. End Sub
  2880.  
  2881.  
  2882. Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
  2883.    'UserControl.SetFocus
  2884.    ' Debug.Print "MouseDown"
  2885. End Sub
  2886. Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  2887.     
  2888.     ' Read Properties:
  2889.     
  2890.     ' Window properties:
  2891.     m_bSorted = PropBag.ReadProperty("Sorted", False)
  2892.     Style = PropBag.ReadProperty("Style", ecsDropDownList)
  2893.     
  2894.     ' Whether the client is going to draw the control:
  2895.     ClientDraw = PropBag.ReadProperty("ClientDraw", ecdNoClientDraw)
  2896.     If (m_eClientDraw = ecdFontPicker) Then
  2897.         m_bSorted = True
  2898.     End If
  2899.     Dim sFnt As New StdFont
  2900.     sFnt.Name = "MS Sans Serif"
  2901.     sFnt.Size = 8
  2902.     Set Font = PropBag.ReadProperty("Font", sFnt)
  2903.     
  2904.     ' Create the owner drawn control:
  2905.     pInitialise
  2906.     
  2907.     Select Case m_eClientDraw
  2908.     Case ecdSysColourPicker
  2909.         pInitialiseSysColors
  2910.     Case ecdFontPicker
  2911.         LoadFonts
  2912.     End Select
  2913.     
  2914.     ' Appearance properties:
  2915.     m_bExtendedUI = PropBag.ReadProperty("ExtendedUI", False)
  2916.     m_lWidth = PropBag.ReadProperty("DropDownWidth", 0)
  2917.     ForeColor = PropBag.ReadProperty("ForeColor", &H80000008)
  2918.     BackColor = PropBag.ReadProperty("BackColor", &H80000005)
  2919.     Enabled = PropBag.ReadProperty("Enabled", True)
  2920.     'BorderStyle = PropBag.ReadProperty("BorderStyle", ecbBorderStyle3d)
  2921.     
  2922.     ' If we are in run time, then start subclassing:
  2923.     If (UserControl.Ambient.UserMode) Then
  2924.         pSubClass
  2925.         ExtendedUI = m_bExtendedUI
  2926.     End If
  2927.     
  2928.     m_bFontNotCreated = True
  2929.         
  2930. End Sub
  2931.  
  2932. Private Sub UserControl_Resize()
  2933.     ' If we have a child combo box control:
  2934.     If (m_hWnd <> 0) Then
  2935.         ' Resize it to fit the space:
  2936.         Dim lW As Long, lH As Long
  2937.         If (m_eStyle And ecsListBox) = ecsListBox Then
  2938.             lH = UserControl.ScaleHeight \ Screen.TwipsPerPixelY
  2939.         Else
  2940.             lH = 11 * Screen.TwipsPerPixelY
  2941.         End If
  2942.         lW = UserControl.ScaleWidth \ Screen.TwipsPerPixelX
  2943.         MoveWindow m_hWnd, 0, 0, lW, lH, 1
  2944.         
  2945.         If (m_eStyle = ecsDropDownCombo) Then
  2946.             SelLength = 0
  2947.         End If
  2948.     End If
  2949. End Sub
  2950.  
  2951. Private Sub UserControl_Terminate()
  2952.     pTerminate
  2953.     Debug.Print "OwnerDraw:Terminate"
  2954. End Sub
  2955.  
  2956. Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
  2957.     With PropBag
  2958.         .WriteProperty "Sorted", Sorted, False
  2959.         .WriteProperty "ExtendedUI", ExtendedUI, False
  2960.         .WriteProperty "DropDownWidth", DropDownWidth, False
  2961.         Dim sFnt As New StdFont
  2962.         sFnt.Name = "MS Sans Serif"
  2963.         sFnt.Size = 8
  2964.         .WriteProperty "Font", Font, sFnt
  2965.         .WriteProperty "ForeColor", ForeColor, &H80000008
  2966.         .WriteProperty "BackColor", BackColor, &H80000005
  2967.         .WriteProperty "ClientDraw", ClientDraw, ecdNoClientDraw
  2968.         .WriteProperty "Style", Style, ecsDropDownList
  2969.         .WriteProperty "Enabled", Enabled, True
  2970.         '.WriteProperty "BorderStyle", BorderStyle, ecbBorderStyle3d
  2971.     End With
  2972. End Sub
  2973.  
  2974.